人,只有自己站起来,这个世界才能属于他。|

园龄:粉丝:关注:

CF Round 1004 题解合集

here.

here.

感觉是 good round。

2C

唯一没做明白的题。

经过若干手玩,发现在最优次数内达到目标,加的值是固定的。

也就是说,如果我加了 9,想要达到目标,以后不可能再加 99

又因为感觉答案上界很小,所以直接暴搜即可。

复杂度 O()

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=1e9;
const int a[10]={9,99,999,9999,99999,999999,9999999,99999999,999999999,9999999999};
int t,n,ans;
bool check(int n){
	while(n){
		if(n%10==7) return true;
		n/=10;
	}
	return false;
}
void dfs(int step,int n,int i){
	if(step>=ans) return;
	if(check(n)){
		ans=min(ans,step);
		return;
	}
	dfs(step+1,n+a[i],i);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n;
		ans=inf;
		for(int i=0;i<=9;i++){
			dfs(0,n,i);
		}
		cout<<ans<<'\n';
	}
	return 0;
}

2D & 1A

趣味交互题。

首先,如果 x 不是一个排列,那么我们询问不在 x 中的数和任意数,返回 0 确定是 A,否则确定是 B

然后,考虑 x 是排列的情况。此时如果是 A,那么图一定是一棵内向基环树森林。

考虑图上两个点如果相互可达且距离相等,那么它们一定在同一个环上,并且距离的上界是 n2

所以我们选择 xi=1xj=n 的两点询问,就可以确定是 A 还是 B

#include<bits/stdc++.h>
using namespace std;
int t,n,a[200005],vis[200005],out;
void solve1(){
	int p,ans;
	if(out==n) p=n-1;
	else p=out+1;
	cout<<"? "<<out<<' '<<p<<endl;
	cin>>ans;
	if(ans==0) cout<<"! A"<<endl;
	else cout<<"! B "<<endl;
} 
void solve2(){
	int minn,maxn,ans1,ans2;
	for(int i=1;i<=n;i++){
		if(a[i]==1) minn=i;
		if(a[i]==n) maxn=i;
	}
	cout<<"? "<<minn<<' '<<maxn<<endl;
	cin>>ans1;
	cout<<"? "<<maxn<<' '<<minn<<endl;
	cin>>ans2;
	if(ans1>=n-1 && ans1==ans2) cout<<"! B"<<endl;
	else cout<<"! A"<<endl;
}
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			vis[a[i]]=1;
		}
		for(int i=1;i<=n;i++){
			if(!vis[i]) out=i;
		}
		if(out) solve1();
		else solve2();
		for(int i=1;i<=n;i++){
			vis[i]=0;
		}
		out=0;
	}
	return 0;
}

2E & 1B

首先注意到,非 0 的数一定都能选。

然后注意到,0 至多只能选一个。

最后注意到,选择靠前的 0,结果一定不劣于选择靠后的 0

然后做完了。我们只需要判断选择第一个 0 和其他非 0 数,形成的子序列的合法性。

扫两边求前缀 min 和后缀 mex 即可。

总体复杂度 O(n)

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
int t,n,flag,a[200005],minn[200005],mexn[200005],cnt[200005],ans;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			if(a[i]) ans++;
		}
		if(ans==n){
			cout<<ans<<'\n';
			ans=0;
			continue;
		}
		flag=false;
		for(int i=1;i<=n;i++){
			if(!a[i] && !flag) flag=true;
			else if(!a[i]) a[i]=inf;
		}
		minn[0]=inf;
		for(int i=1;i<=n;i++){
			minn[i]=min(minn[i-1],a[i]);
		}
		for(int i=n;i>=1;i--){
			mexn[i]=mexn[i+1];
			if(a[i]<=n) cnt[a[i]]=1;
			while(cnt[mexn[i]]) mexn[i]++; 
		}
		flag=false;
		for(int i=1;i<n;i++){
			if(minn[i]<mexn[i+1]) flag=true; 
		}
		if(!flag) ans++;
		cout<<ans<<'\n';
		ans=0;
		for(int i=0;i<=n;i++){
			minn[i]=mexn[i]=cnt[i]=0;
		}
	}
	return 0;
}

2F & 1C

题面有点神秘。

实际上就是让你对每次操作后,都有 (P,Q,R) 中两者相等。

不妨设 prei=j=1iaj

又因为第 i 次操作后,PQR=prei,所以 (P,Q,R) 一定形如 (prei,x,x)(x,prei,x)(x,x,prei)

考虑 DP,设 fi,x 表示前 i 次操作后,(P,Q,R) 形如 (prei,x,x)(x,prei,x)(x,x,prei) 的方案数。

考虑因为 xaix,所以当 xprei1fi,x=fi1,x

所以只需要考虑 x=prei1 的情况。

考虑怎样的三元组可以通过一次操作到 fi,prei,发现只有 fi1,prei1fi1,prei,也就是说:

fi,x=3fi1,prei1+2fi1,prei,x=prei1

fi,x=fi1,x,xprei1

答案就是 xfn,x

然后把第一维压了,用 umap 维护合法状态,总体复杂度 O(n)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int t,n,a[200005],pre[200005],ans;
map<int,int> f;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			pre[i]=pre[i-1]^a[i];
		}
		f[0]=1;
		for(int i=1;i<=n;i++){
			f[pre[i-1]]=(3*f[pre[i-1]]%mod+2*f[pre[i]]%mod)%mod;
		}
		for(map<int,int>::iterator it=f.begin();it!=f.end();it++){
			ans=(ans+it->second)%mod;
		}
		cout<<ans<<'\n';
		ans=0;
		f.clear();
	}
	return 0;
}

1D1

趣味组合题。

考虑从小到大考虑每个人,对于当前第 i 个人,他所能选择的位置是大小为 c 的位置集合的一个子集,因为编号小的人不会对编号大的人产生任何影响。

因此,考虑 DP。设 fi,j 表示考虑前 i 个人,确定了 j 个位置的方案数。

不难得到转移:

fi,j=k=0c(ck)fi1,jk

初始 f1,c=1

需要滚动数组,总体复杂度 O(nmc)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int t,n,m,c,x,f[2][10001],C[101][101];
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	C[0][0]=1;
	for(int i=1;i<=100;i++){
		C[i][0]=1;
		for(int j=1;j<=i;j++){
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
		}
	}
	cin>>t;
	while(t--){
		cin>>n>>c>>m;
		for(int i=1;i<=m;i++){
			cin>>x;
		}
		for(int i=0;i<=m;i++){
			f[0][i]=f[1][i]=0;
		}
		f[1][c]=1;
		for(int i=2;i<=n;i++){
			for(int j=0;j<=m;j++){
				f[i&1][j]=0;
			}
			for(int j=0;j<=m;j++){
				for(int k=0;k<=min(c,j);k++){
					f[i&1][j]=(f[i&1][j]+C[c][k]*f[(i-1)&1][j-k]%mod)%mod;
				}
			}
		} 
		cout<<f[n&1][m]<<'\n';
	}
	return 0;
}

本文作者:Kenma

本文链接:https://www.cnblogs.com/Kenma/p/18712573

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Kenma  阅读(12)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起