25-08-07 CSP-J冲刺 模考总结

本次模考共4题 我的得分情况如下

张的弓
<19503
绝对公平
<21048>
AI作曲
<21039>
小信的特工行动
<21002>
Accepted 100 分 Accepted 100 分 Time Limit Exceeded 30分 Time Limit Exceeded 55分

T1难度 :heart:

经过分析 我们可以将行走步数简化为

x个从(1,2n)到(1,2n+2)的过程

x=k/(n*2)

剩余y步

y=kmod(n*2)

如果y<n 就说明第k步走到了(2*x+1,1+y)

如果y>=n 就说明第k步走到了(2*x+2,2*n-y)


\Delta (A,B)=\begin{cases} 2*x+y (y<n) \\ 2*x+2*n-y(n \le y<n*2) \end{cases}
具体代码如下

if(y<n) cout<<2*x+y<<endl;
else cout<<2*x+2*n-y<<endl;

T2 难度 :heart:

读完题后我们不难发现 如果想让所以数字的值相等

就要保证每个质因数的个数必须为n的倍数

该题就变的简单多了

核心代码如下

void pri(int x){
	while(x!=1){
		for(int i=2;i<=x;i++){
			if(x%i==0){
				facto[i]++;
				x/=i;
				maxx=max(maxx,i);
				break;
			}
		}
	}
}

T3难度 :heart: :heart: :heart:

该题的30分是不难拿到的
只需暴力搜索时考虑好边界即可

void dfs(int l,int r,int sum){
	if(l==r+1){
		maxx=max(maxx,sum+score[a[l-1]][a[l]]);
		return ;
	}
	for(int i=1;i<=m;i++){
		int now_sum=sum+score[a[l-1]][i];
		a[l]=i;
		dfs(l+1,r,now_sum);
		a[l]=-1;
	}
}

正数为我们将整首乐谱自然地分成了几个区域

我们只需遍历两个整数间连续的负数区域即可

(其中l,r分别代表负数区域的起始和结束位置)

要将30分改为100分需要一点小小的思维转变

先设置一个二维数组dp[i][j]

(i,j分别表示当前下标和a[i]中的音符,dp[i][j]中存储的是当a[i]=j时当前最好情况)

所以我们只需分四种情况讨论

1. 当a[i]>0且a[i-1]>0时
因为此时的a[i]和a[i-1]的值都是固定的
所以
dp[i][a[i]]=dp[i-1][a[i-1]]+score[a[i-1][a[i]]

2. 当a[i]>0且a[i-1]<0时
此时我们需枚举a[i-1]的值j
dp[i][a[i]]=max(dp[i][a[i]],dp[i-1][j]+score[j][a[i]])

3. 当a[i]<0且a[i-1]>0时
此时我们需枚举a[i]的值j
dp[i][j]=max(dp[i][j],dp[i-1][a[i-1]]+score[a[i-1][j])

4. 当a[i]<0且a[i-1]<0时
此时我们需枚举a[i-1]的值j和a[i]的值k
dp[i][k]=max(dp[i][k],dp[i-1][j]+score[j][k])

具体代码如下

for(int i=2;i<=n;i++){
	if(a[i]>0){
		if(a[i-1]>0){
			dp[i][a[i]]=dp[i-1][a[i-1]]+score[a[i-1]][a[i]];
		}
		else{
			for(int j=1;j<=m;j++){
				dp[i][a[i]]=max(dp[i][a[i]],dp[i-1][j]+score[j][a[i]]);
			}
		}
	}
	else{
		if(a[i-1]>0){
			for(int j=1;j<=m;j++){
				dp[i][j]=max(dp[i][j],dp[i-1][a[i-1]]+score[a[i-1]][j]);
			}
		}
		else{
			for(int j=1;j<=m;j++){
				for(int k=1;k<=m;k++){
					dp[i][k]=max(dp[i][k],dp[i-1][j]+score[j][k]);
				}
			}
		}
	}
}

T4 难度:heart: :heart: :heart:

读完题后观察到要对2^64取模 这里使用 unsigned long long

暴力搜索可以得到50分

void dfs(int x,unsigned long long sum){
	if(x==n){
		if(sum==s){
			for(int i=0;i<n;i++){
				cout<<ans[i];
			}
			flag=1;
		}
		return ;
	}
	if(flag==1) return ;
	ans[x]='0';
	dfs(x+1,sum);
	ans[x]='1';
	dfs(x+1,sum+b[x]);
} 

如何从50分改到100分呢

我们需要用到折半搜索以及

unordered_map<unsigned long long,string> mp

进行2次dfs搜索 每次搜索n/2

将第一次搜索的sum和ans放到mp中

第二次搜索结束后查找s-sum的值是否在mp中并执行后续操作

具体代码如下

void dfs1(int x,unsigned long long sum){
	if(x==n/2){
		mp[sum]=ans.substr(0,n/2);
		return ;
	}
	ans[x]='0';
	dfs1(x+1,sum);
	ans[x]='1';
	dfs1(x+1,sum+b[x]);
}

void dfs2(int x,unsigned long long sum){
	if(x==n){
		unsigned long long tem=s-sum;
		if(mp.count(tem)){
			cout<<mp[tem]<<ans.substr(n/2,n-n/2);
		}
		return ;
	}
	ans[x]='0';
	dfs2(x+1,sum);
	ans[x]='1';
	dfs2(x+1,sum+b[x]);
}

在主函数中别忘记给ans定义初始长度

今天的四道题就分享到这里了

希望我的分享能给大家提供灵感 :face_without_mouth:

(帖子已被作者删除)

(帖子已被作者删除)

二维数组要写成 a_{i,j},变量名不用 TeX