正在加载今日诗词....

Codeforces Round #744 (Div. 3) (CF1579) 题解

CF1579E2. Array Optimization by Deque
题意
给一组数据放入deque中(可以从前面放,也可以从后面),要使逆序数最少。
解法
可以发现,前面的放入顺序对后面的每一个数产生的逆序数没有影响。所以直接贪心,每个数选择最好的位置放进去。注意要离散化。

#include <bits/stdc++.h>
#define int long long
#define lb(x) (x&(-x))
#define For(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=800005;
int t,n,a[N],tt[N],f[N];
void add(int x) {
    for(int i=x;i<=N;i+=lb(i)) f[i]++;
}
int query(int x) {
    int ans=0;
    for(int i=x;i;i-=lb(i)) ans+=f[i];
    return ans;
}
signed main() {
    cin>>t;
    while(t--) {
        memset(f,0,sizeof f);
        cin>>n;
        For(i,1,n) {
        	cin>>a[i];
			tt[i]=a[i];	
        }
        sort(tt+1,tt+n+1);
        int m=unique(tt+1,tt+n+1)-tt-1;
        For(i,1,n) a[i]=lower_bound(tt+1,tt+m+1,a[i])-tt;
        int ans=0;
        For(i,1,n) {
            ans+=min(query(a[i]-1ll),(i-1)-query(a[i]));
            add(a[i]);
        }
		cout<<ans<<'\n';
    }
}
//3 5 5 6 7 9
//adding 6
//front->3 back->2

CF1579F. Array Stabilization (AND version)
题意
有一个01数组,给出d,每次操作即把原先的数组与数据右移d位后的数组进行and操作。问几轮后数据变为全0。
解法
考虑一个1变成0的情况,即a[i]=1 && a[i+d]=0。所以用i+d→i的顺序进行BFS,搜索总层数即为答案。

#include <bits/stdc++.h>
#define For(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=1000005;
int t,n,d,mx;
struct node {
    int v,s;
} a[N];
queue <int> q;
signed main() {
    cin>>t;
    while(t--) {
        memset(a,0,sizeof a);
        cin>>n>>d;
        For(i,0,n-1) cin>>a[i].v;
        while(!q.empty()) q.pop();
        mx=0;
        For(i,0,n-1) if(a[i].v==0 && a[(i-d+n)%n].v==1) {
            q.push(i);
        }
        while(!q.empty()) {
            int now=q.front();
            q.pop();
            if(a[(now-d+n)%n].v==1) {
                a[(now-d+n)%n]=(node) {0,a[now].s+1};
                q.push((now-d+n)%n);
                mx=max(mx,a[now].s+1);
            }
        }
        bool flag=1;
        For(i,0,n-1) if(a[i].v==1) flag=0;
        if(flag==1) cout<<mx<<'\n'; else puts("-1");
    }
    return 0;
}

CF1579G. Minimal Coverage
题意
有一些棍子,前后相连,每一根可以向左或向右,求覆盖的长度的最小值。
解法
来源

几个当时疑惑的点再写一下:
倒数第四行的max(dp[i][l]-a[i+1],0)可以看成与上面的左边界max(l-a[i+1],0)一样的道理。就是说:如果现在使用的数据超出了原本最优解限定的范围,就默认它现在已经是极左(右)点。

//f[i][j]:到i位且当前距离左端点j时,到右端点的长度
//太难了太难了 动态规划一生之敌
#include <bits/stdc++.h>
#define For(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=10005;
int t,n,a[N],f[N][2005],mx;
signed main() {
    cin>>t;
    while(t--) {
        cin>>n;
        mx=0;
        For(i,1,n) {cin>>a[i]; mx=max(mx,a[i]);}
        For(i,1,n) For(j,0,2*mx) f[i][j]=0x3f3f3f3f;
        f[0][0]=0;
        For(i,0,n-1) For(j,0,2*mx) {
            f[i+1][max(0,j-a[i+1])]=
                min(f[i+1][max(0,j-a[i+1])],f[i][j]+a[i+1]);
            if(j+a[i+1]<=2000) f[i+1][j+a[i+1]]=
                min(f[i+1][j+a[i+1]],max(f[i][j]-a[i+1],0));
        }
        int ans=0x3f3f3f3f;
        For(i,0,2*mx) ans=min(ans,i+f[n][i]);
        cout<<ans<<'\n';
        
    }
    return 0;
}
posted @ 2021-11-03 19:31  wky32768  阅读(97)  评论(0编辑  收藏  举报