CodeForces 1615F LEGOndary Grandmaster

题目传送门

我们先考虑如果没有 ?,这个问题应该怎么做。

考虑到翻转两个相邻且相同的位置是困难的,但是我们如果吧所有奇数位置上的数翻转,就变成了交换两个相邻的数,这个东西显然是好做的。

这个东西有解就是两个串中的 1 个数相同,需要的次数就是把每个 1 的位置摘出来,然后对位的两个数的差的绝对值之和。

于是我们会做没有 ? 的情况了。

但是这个东西,显然不好在有 ? 的情况下统计,所以我们还需要转化。

对于没有 ?\(s,t\),设 \(a_i\)\(s\) 中前 \(i\) 个位置中 1 的个数,\(b_i\)\(t\) 中前 \(i\) 个位置中 1 的个数,则我们的交换次数也可以表示成 \(\sum |a_i-b_i|\)

于是我们直接 dp 即可,设 \(f_{i,j}\) 表示前 \(i\) 个位置 \(a_i-b_i=j\) 的方案数,\(g_{i,j}\) 相当于把整个串反转过来的 \(f_{i,j}\)。转移显然。

于是答案就是 \(\displaystyle\sum_{i=1}^{n-1}\sum_{j=-n}^{n}(f_{i,j}\times g_{i+1,-j}\times |j|)\)

AC code:

#include<bits/stdc++.h>
#define int long long
#define N 2005
#define mod 1000000007
#define pii pair<int,int>
#define x first
#define y second
using namespace std;
int T=1,n,f[N][N<<1],g[N][N<<1];
char s[N],t[N];
bool check(char a,int b){
	if(a=='?')return 1;
	return a-'0'==b;
}
void solve(int cs){
	cin>>n>>s+1>>t+1;
	for(int i=1;i<=n;i+=2){
		if(s[i]=='1')s[i]='0';
		else if(s[i]=='0')s[i]='1';
		if(t[i]=='1')t[i]='0';
		else if(t[i]=='0')t[i]='1';
	}
	for(int i=0;i<=n+1;i++){
		for(int j=0;j<=n*2;j++){
			f[i][j]=g[i][j]=0;
		}
	}
	f[0][n]=1;
	for(int i=0;i<n;i++){
		for(int j=0;j<=n*2;j++){
			for(int u=0;u<2;u++){
				for(int v=0;v<2;v++){
					if(check(s[i+1],u)&&check(t[i+1],v)&&j+u-v>=0&&j+u-v<=n*2){
						(f[i+1][j+u-v]+=f[i][j])%=mod;
					}
				}
			}
		}
	}
	g[n+1][n]=1;
	for(int i=n+1;i>1;i--){
		for(int j=0;j<=n*2;j++){
			for(int u=0;u<2;u++){
				for(int v=0;v<2;v++){
					if(check(s[i-1],u)&&check(t[i-1],v)&&j+u-v>=0&&j+u-v<=n*2){
						(g[i-1][j+u-v]+=g[i][j])%=mod;
					}
				}
			}
		}
	}
	int res=0;
	for(int i=1;i<n;i++){
		for(int j=-n;j<=n;j++){
			(res+=f[i][n+j]*g[i+1][n-j]%mod*abs(j)%mod)%=mod;
		}
	}
	cout<<res<<'\n';
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>T;
//	init();
	for(int cs=1;cs<=T;cs++){
		solve(cs);
	}
	return 0;
}
posted @ 2025-03-26 19:09  zxh923  阅读(8)  评论(0)    收藏  举报