20251030模拟赛

T1

小模拟题,场切了。

T2

有一个只含 \(0,1\) 的字符串 \(s\),在其中选择两个子串 \(t1\)\(t2\),要求 \(t1\oplus t2\) 最大并输出这个二进制表示。

你说的对,但 \(1\le |s|\le 10^7\)


首先前导 \(0\) 是没用的,可以全部去掉。

然后第一个子串肯定是取去掉前导 \(0\) 的串。

第二个字符串要看出现的第一个 \(0\),设从这个位置到结尾的子串为 \(t\),要找一个长度与 \(t\) 相同的子串使得它异或 \(t\) 最大。

场上用的是将所有长度符合的字串放进 trie 树来找,时间复杂度 \(\mathcal O(n^2)\)

但其实可以直接贪心做到 \(\mathcal O(n)\)

其实我也不是很理解,这里直接放官解:

再考虑 \(t\) 右边最长的相邻的一整块 \(0\),记它们的右边界为 \(v\),在理想情况下我们让 \(t\) 中的 \(0\) 都能变
\(1\),同时利用 \(t~v\) 这些 \(0\)\(v\) 右边的第一个 \(1\) 不受影响。可以发现这种取法是唯一的并且一定最
优,只要让 \(max(\text{第一个} 1 \text{的位置},t-(t-v+1))\) 作为第一个串的开头就行了。

#include<bits/stdc++.h>
#define N 10000005
#define getc getchar_unlocked 
#define putc putchar_unlocked
using namespace std;
int n,a[N];
int main(){
	int T;scanf("%d",&T);
	while(T--){
		int u=-1,v=-1,t,res;
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			char c;
			do c=getc();
			while(c!='0'&&c!='1');
			a[i]=c=='1';
			if(a[i]&&u==-1) u=i;
			if(!a[i]&&u!=-1&&v==-1) v=i;
		}
		if(u==-1){puts("0");continue;}
		if(v==-1){
			for(int i=u;i<n;i++) putc('1');
			putc(u==1?'0':'1');
			puts("");continue;
		}
		for(t=v;!a[t+1];t++);
		res=max(u,(v<<1)-t-1);
		for(int i=u;i<=n;i++){
			if(i<v) putc(a[i]?'1':'0');
			else putc((a[i]^a[res+i-v])?'1':'0');
		}
		puts("");
	}
	return 0;
}

T3

序列中有 \(n\) 个值域在 \([1,m]\) 的正整数,每次可以将形如 \((x,x,x)\)\((x,x+1,x+2)\)\(x\) 为正整数)的三个数合并成一组,求将整个序列全部合并成 \(\dfrac{n}{3}\) 组的方案数模 \(10^9+7\)

自认为比 T2 简单。

容易发现合并与位置无关,于是记 \(a_i\)\(i\) 的出现次数。

可以想到每个数 \(x\) 只能与 \([x-2,x+2]\) 的数进行合并,也就是说考虑它的合并时只会影响前后 \(2\) 个数,可以 DP。

\(f_{i,j,k}\) 为当前考虑数 \(i\)\(i\) 还没有合并,\(i-2\) 及比它小的的已经全部合并完),\(i\) 剩下 \(j\) 个,\(i-1\) 剩下 \(k\) 个的方案数。

转移方程为:

\[f_{i,j,k}= \\ f_{i,j+3,k}(\text{选} (i,i,i) \text{合并}) \\ +f_{i-1,k+a_i-j,a_i-j}(\text{选} a_i-j \text{个} (i-2,i-1,i) \text{合并}) \]

直接做的话空间是 \(\mathcal O(n^2m)\) 的,滚动一下第一维变成 \(\mathcal O(n^2)\)

注意转移方程中要用到 \(j+3\)\(k+a_i-j\),所以要从大往小枚举。

滚动了数组记得清空。

时间复杂度 \(\mathcal O(\sum_{i=1}^n a_i)\le \mathcal O(n^2)\)

#include<bits/stdc++.h>
#define N 5005
using namespace std;
const int mod=1000000007;
int n,m,a[N],f[2][N][N];
void upd(int &x,int y){
	x+=y;
	while(x>=mod) x-=mod;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1,x;i<=n;i++)
		scanf("%d",&x),a[x]++;
	f[0][0][0]=1;
	for(int i=1;i<=m;i++){
		bool x=i&1,y=i&1^1;
		for(int j=a[i];j>=0;j--){
			int v=a[i]-j;
			for(int k=min(a[i-1]-v,j);k>=0;k--)
				upd(f[x][j][k],f[y][k+v][v]);
		}
		for(int j=a[i]-3;j>=0;j--)
			for(int k=min(a[i-1],j);k>=0;k--)
				upd(f[x][j][k],f[y][j+3][k]);
		if(i==1) f[0][0][0]=0;
		else
			for(int j=0;j<=a[i-1];j++)
                for(int k=min(a[i-2],j);k>=0;k--)
					f[y][j][k]=0;
	}
	printf("%d",f[m&1][0][0]);
    return 0;
}
posted @ 2025-10-30 15:47  Jokersen  阅读(8)  评论(0)    收藏  举报