Codeforces Round 959 sponsored by NEAR (Div. 1 + Div. 2)
可惜还是只能 VP。好像这场的 E 重了所以有很多人打差评?
A. Diverse Game
简单的。直接将每个数 就行了,如果为 就变为 。
B. Fun Game
一开始读错题了。考虑分别找到 中第一个 的位置,若 中的位置大于等于 中的位置那么有解,反之无解。记 中第一个 位置为 ,考虑每次操作选取区间都形如 ,手玩可以发现这个操作可以代替其他所有操作,所以只要 前面没有要修改成 的地方就行了。
C. Hungry Games
计数题,考虑 dp。设 表示以 为起点的非法子串数,考虑填表法,做一遍前缀和,每次转移时可以二分得到第一个使 区间和大于 的位置 ,从 处转移 ,如果到了一个 使得 就 break,答案就是 。注意 dp 初值赋为 。
这个其实和官解差不多的。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2*114514,M=1919810;
ll T;
ll n,m,k,a[N],sum[N],dp[N]; //以i开头的不合法子串个数?
string s,t;
void solve(){
cin>>n>>k;
dp[0]=1;
for(int i=1;i<=n;++i) cin>>a[i],sum[i]=sum[i-1]+a[i],dp[i]=1;
ll pos=1,ans=n*(n+1)/2;
for(int i=1;i<=n;++i){
if(sum[i-1]+k>=sum[n]) break;
ll j=upper_bound(sum+i,sum+n+1,sum[i-1]+k)-sum;
ans-=dp[i-1],dp[j]+=dp[i-1];
}
cout<<ans<<'\n';
}//红温了
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>T;
while(T--) solve();
return 0;
}
D. Funny Game
明显 越小能连的边就越多,所以可以考虑从大到小枚举 建边。建树肯定要加一个并查集来判断,根据鸽巢原理(或者手玩得到),这 个点中一定存在一对能连边的点,那么我们便枚举一个点 ,开数组记录下模 相同且不连通的点,然后并查集维护连通性,最后再倒着输出就可以了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pi pair<ll,ll>
#define fi first
#define se second
const ll N=2*114514,M=1919810;
ll T;
ll n,m,k,a[N],f[N],p[N];
ll find(ll x){
return x==f[x]?x:f[x]=find(f[x]);
}
vector <pi> out;
void solve(){
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i],f[i]=i;
out.clear();
cout<<"YES\n";
for(int i=n-1;i>=1;--i){
ll u=0,v=0;
for(int j=0;j<=n;++j) p[j]=0;
for(int j=1;j<=n;++j){
if(j!=find(j)) continue;
ll ux=a[find(j)]%i;
if(p[ux]!=0){
u=p[ux],v=find(j);
break;
}
p[ux]=find(j);
}
//cout<<u<<" "<<v<<'\n';
out.push_back({u,v});
ll x=find(u),y=find(v);
if(x!=y) f[y]=x;
}
for(int i=out.size()-1;i>=0;--i) cout<<out[i].fi<<" "<<out[i].se<<'\n';
}//红温了
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>T;
while(T--) solve();
return 0;
}
E. Wooden Game
看了题解。我们发现对于一棵树,假设它足够大,只要不断删除叶节点再删除更大的子树就能凑出二进制上的每一位,从而使或的和最大,也就是说答案是和树的形态无关,只和大小有关的。
然后就显然了。从高到低枚举答案在二进制上的每一位,然后枚举哪颗树可以凑出这一位。令当前位数为 对于一棵树,如果凑不出就 continue,否则若答案此为也为 ,那么就让答案与上 1<<i
;若答案为 的话就可以让 后面的所有位都与上 ,这样的答案就是最优的。
复杂度 。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pi pair<ll,ll>
#define fi first
#define se second
const ll N=1145140,M=1919810;
ll T;
ll n,m,k,x,a[N];
bool cmp(ll x,ll y){
return x>y;
}
void solve(){
cin>>k;
for(int i=1;i<=k;++i){
cin>>a[i];
for(int j=1;j<a[i];++j) cin>>x;
}
sort(a+1,a+k+1,cmp);
ll ans=0;
for(int i=1;i<=k;++i){
for(int j=24;j>=0;--j){
ll f1=ans>>j&1,f2=a[i]>>j&1;
if(f2==0) continue;
if(f1==0) ans|=1<<j;
else{
ans|=(1<<j)-1;
break;
}
}
}
cout<<ans<<'\n';
}//红温了
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>T;
while(T--) solve();
return 0;
}
F. Stardew Valley
没看了