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。那这里选择的长度就对异或的结果有影响了。后来又重新读了一遍题目,发现读错了,悲,呜呜。

切入正题,我们能很容易的发现,只选择区间为12的区间进行是最值得的。理解起来也比较容易,假设我们选择了一个区间的长度为len,则其需要的时间为len/2上取整,我们可以等价的将len拆分为若干个21,则时间是一样的。

另外,我们可以发现,如果一个区间的区间异或和为0,那么把这个区间变为0的所用时间为:区间长度-1

这点也很好理解,我们可以从最左向右一个个异或过去,等价于是将整个区间从左到右一个个合并,总共只需要len-1的时间。

我们设dp[i]:把前i个数变为0的最短时间

因此我们可以考虑怎么转移。

  1. 首先可以不管前面怎么样,直接花一费把i位置零
  2. 接下来,我们只要看是否有以该位结尾的最后一个区间其区间异或值为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;
}
posted @ 2022-09-16 22:57  艾特玖  阅读(27)  评论(0)    收藏  举报