Codeforces Round #814 (Div. 2)
Codeforces Round #814 (Div. 2)
D2. Burenka and Traditions (hard version)
题目大意
给你一个长度为n的数组,每次选一个区间[l,r],把他们都异或上同一个数x,时间代价为(r-l+1)/2,问把数组全变成0的最低花费时间是多少。
分析
刚开始读错题了,以为一次操作选择[l,r]之后,我们必须对整个区间的所有数异或(r-l+1)/2次选择的x。那这里选择的长度就对异或的结果有影响了。后来又重新读了一遍题目,发现读错了,悲,呜呜。
切入正题,我们能很容易的发现,只选择区间为1和2的区间进行是最值得的。理解起来也比较容易,假设我们选择了一个区间的长度为len,则其需要的时间为len/2上取整,我们可以等价的将len拆分为若干个2与1,则时间是一样的。
另外,我们可以发现,如果一个区间的区间异或和为0,那么把这个区间变为0的所用时间为:区间长度-1。
这点也很好理解,我们可以从最左向右一个个异或过去,等价于是将整个区间从左到右一个个合并,总共只需要len-1的时间。
我们设dp[i]:把前i个数变为0的最短时间。
因此我们可以考虑怎么转移。
- 首先可以不管前面怎么样,直接花一费把
i位置零 - 接下来,我们只要看是否有以该位结尾的最后一个区间其区间异或值为0,找到这个区间也容易,只要记住每个前缀异或值对应的最后一个位置是
pos,则这个区间即为[pos,i],即可从dp[pos]转移过来,转移方程为dp[pos]+i-pos-1。
这就结束了,我们来看看代码。
Ac_code
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
typedef long long LL;
using namespace std;
const int N = 1e5 + 10,M = N*2;
void solve() {
int n;cin>>n;
vector<int> a(n+1),dp(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
map<int,int> mp;
mp[0] = 0;dp[0] = 0;
for(int i=1;i<=n;i++)
{
a[i] ^= a[i-1];
dp[i] = dp[i-1] + 1;
if(mp.count(a[i])) dp[i] = min(dp[i],dp[mp[a[i]]]+i-mp[a[i]]-1);
mp[a[i]] = i;
}
cout<<dp[n]<<'\n';
}
int main()
{
ios;
int T=1;
cin>>T;
while(T -- ) {
solve();
}
return 0;
}
E. Fibonacci Strings
题目大意
给定一个长度为n的数组,每个数字a[i]表示i这个字符串出现了a[i]次,请问能够构造出一个斐波那契字符串,类似于abccdddeeeee这样的形式,每一块内只能出现相同字符并且相邻的块内不能出现同一种字符。
分析
因为我们要恰好凑出斐波那契字符串,因此我们需要知道,斐波那契数组,以及其前缀和所对应的为前多少项。
接下来就是贪心的思路了。
我们考虑从大到小取用不同的字符,这可以用一个堆来维护,但如何保证相同的不连续呢?
我们可以用一个变量暂存上一个字符用完后还剩下的数量,先不放回堆里,等下一个取用完之后,再放入。
什么情况是NO?考虑,某一次取用,凑不够我们需要用的数量了,或者是取用的时候,堆内已经空了,则是NO。
Ac_code
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
typedef long long LL;
using namespace std;
const int N = 110,M = N*2;
int n,m,a[N];
int f[N];
map<int,int> mp;
void init()
{
f[0] = f[1] = 1;
mp[1] = 0,mp[2] = 1;
int sum = 2;
for(int i=2;i<100;i++)
{
f[i] = f[i-1] + f[i-2];
sum += f[i];
mp[sum] = i;
}
}
void solve() {
cin>>n;
priority_queue<int> q;
int sum = 0;
for(int i=1;i<=n;i++) cin>>a[i],sum += a[i],q.push(a[i]);
m = mp[sum];
if(m>0||sum==1)
{
int tmp = -1;
for(int i=m;i>=0;i--)
{
if(!q.size())
{
cout<<"NO\n";
return ;
}
auto t = q.top();
q.pop();
if(t<f[i])
{
cout<<"NO\n";
return ;
}
if(tmp!=-1) q.push(tmp);
tmp = t - f[i];
}
cout<<"YES\n";
return ;
}
cout<<"NO\n";
}
int main()
{
ios;
int T=1;
cin>>T;
init();
while(T -- ) {
solve();
}
return 0;
}
F. Tonya and Burenka-179
分析
Ac_code
#include <bits/stdc++.h>
#define fi first
#define se second
#define endl '\n'
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
typedef long long LL;
using namespace std;
const int N = 2e5 + 10,M = N*2;
//可删除堆
struct popheap
{
priority_queue<LL> _add,_del;//其中的方向要相同,可以使大根堆也可以是小根堆
int size()
{
while(!_add.empty()&&!_del.empty()&&_add.top()==_del.top()) _add.pop(),_del.pop();
return _add.size();
}
LL get()
{
while(!_add.empty()&&!_del.empty()&&_add.top()==_del.top()) _add.pop(),_del.pop();
return _add.top();
}
void add(LL x)
{
_add.push(x);
}
void del(LL x)
{
_del.push(x);
}
};
void solve() {
int n,q;cin>>n>>q;
vector<vector<LL>> s(n+1);
vector<LL> a(n+1),fac(n+1);
for(int i=0;i<n;i++) cin>>a[i];
int cnt = 0;
for(int i=2,x=n;i<=x;i++)
if(x%i==0)
{
fac[++cnt] = n/i;
while(x%i==0) x/=i;
}
popheap ph;
for(int i=1;i<=cnt;i++)
{
int k = fac[i];s[i].resize(k);for(int j=0;j<k;j++) s[i][j] = 0;
for(int j=0;j<n;j++) s[i][j%k]+=a[j];
for(int j=0;j<k;j++) ph.add(s[i][j]*k);
}
// cout<<ph._add.top()<<endl;
// return ;
cout<<ph.get()<<'\n';
while(q--)
{
int x,y;cin>>x>>y;--x;
for(int i=1;i<=cnt;i++)
{
int k = fac[i];ph.del(s[i][x%k]*k);
s[i][x%k]+=y-a[x];ph.add(s[i][x%k]*k);
}
a[x]=y;cout<<ph.get()<<'\n';
}
}
int main()
{
ios;
int T=1;
cin>>T;
while(T -- ) {
solve();
}
return 0;
}

浙公网安备 33010602011771号