Codeforces Round #708(Unrated on Div. 2)
好不容易打一场CF结果unrated了,不过这场体验极差确实该unrated,感觉是div3难度
A
签到,先把所有第一次出现的数从小到大排序,剩下的随便排
B
按a[i]%m分类,然后特判0组和m/2(m为偶数时)的组,然后剩下的两两配对即可
#include<bits/stdc++.h> using namespace std; const int N=1e5+7; int n,m,ans,a[N]; int solve(int x,int y) { if(x<y)swap(x,y); if(!x)return 0; if(x==y)return 1; return x-y; } int main() { int T;scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0;i<m;i++)a[i]=0; for(int i=1,x;i<=n;i++)scanf("%d",&x),a[x%m]++; ans=0; if(a[0])ans++; for(int i=1;i<=m/2;i++) if(m%2==0&&i==m/2&&a[i])ans++; else ans+=solve(a[i],a[m-i]); printf("%d\n",ans); } }
C
真正的签到题,k=3时,如果为奇数则是1 n/2 n/2,为4的倍数则是n/4 n/4 n/2,其余情况为2 n/2-1 n/2-1
D
本场最难的题,但依旧很水,就是个O(n^2)的DP,每次搜到i时从i-1往1搜,先反着改变状态,再正着改变状态
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5005; int n,tag[N],a[N]; ll ans,f[N]; int main() { int T;scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&tag[i]); for(int i=1;i<=n;i++)scanf("%d",&a[i]),f[i]=0; ans=0; for(int i=2;i<=n;i++) for(int j=i-1;j;j--) if(tag[i]!=tag[j]) { ll tmp=f[j]; f[j]=max(f[j],f[i]+abs(a[i]-a[j])); f[i]=max(f[i],tmp+abs(a[i]-a[j])); } for(int i=1;i<=n;i++)ans=max(ans,f[i]); printf("%lld\n",ans); } }
E
首先把每个数的所有平方因子去掉,问题就变成了判断序列中不存在相同的2个数,要注意的是判断平方因子时只需要扫到a[i]^(1/3)而不是a[i]^(1/2),否则会被卡常数。k=0时直接搜索即可。考虑k>0,等价于将此数删去,先预处理c[i][j],表示从i开始,删去至多j个数最远走到哪里,这个可以扫描j然后再扫描i发现答案单调就用2-pointers处理,然后直接背包DP即可,复杂度O(n((a[i])^(1/3)+k^2)),其实或许很可能有更优化的做法,但是能过就行了。
#include<bits/stdc++.h> using namespace std; const int N=1e6+7; int n,k,ans,a[N],c[N][21],f[N][21]; short b[N*10]; int main() { int T;scanf("%d",&T); while(T--) { scanf("%d%d",&n,&k); for(int i=1,x,y;i<=n;i++) { scanf("%d",&x),y=1; for(int j=2;j*j*j<=x;j++) { while(x%(j*j)==0)x/=j*j; while(x%j==0)x/=j,y*=j; } int xx=sqrt(x); if(xx*xx==x)a[i]=y;else a[i]=x*y; } for(int i=0;i<=k;i++) { for(int j=1;j<=n;j++)b[a[j]]=0; int p=0,num=0; for(int j=1;j<=n;j++) { if(j>1) { if(--b[a[j-1]])--num; } while(num<=i&&p<=n)if(b[a[++p]]++)++num; c[j][i]=p; } } for(int i=2;i<=n+1;i++)for(int j=0;j<=k;j++)f[i][j]=n; for(int i=1;i<=n;++i) for(int j=0;j<=k;++j) if(f[i][j]<n) for(int t=0;j+t<=k;++t) f[c[i][t]][j+t]=min(f[c[i][t]][j+t],f[i][j]+1); ans=f[n+1][0]; for(int i=1;i<=k;i++)ans=min(ans,f[n+1][i]); printf("%d\n",ans); } }
很没意思的一场,想为下个月初的ICPC练手,可是却是这样垃圾的题目,垃圾到我这种老年痴呆选手都能AK。