「CEOI2019」立方填词,LOJ3164,奇技淫巧?

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Deep_Kevin/article/details/102710470

正题

      Portal

      考场上我只会枚举上下两层的正方形,然后暴力合并。

      这题的题解思考方式很强:

      首先正着反着插进去拍一遍序,去一下重。

      考虑黑白染色,分成两组互不相关的点。

      然后对于一个点,枚举附近三个点的方案数:D[a][b][c]表示有分别一条边连到a,b,c的可选点方案数,我们并不需要在乎当前点是什么。

      上面这个东西可以用(\sum)^4预处理出来。

      枚举一组点(a,b,c,d),贡献的答案显然就是:D[a][b][c]*D[a][b][d]*D[a][c][d]*D[b][c][d]

      接着发现你被卡常了!

      实际可以很容易的减少常数:

      D[a][b][c],D[a][c][b],...,D[c][b][a]六组其实是相等的,所以我们可以保证a<=b<=c来减少大约\frac{5}{6}的预处理常数。

      而枚举(a,b,c,d)也是这样子的。保证a<=b<=c<=d,就会减少大约\frac{24}{23}的求解常数,但是在求解过程中,a,b,c,d实际上是可以调换的,而且可能存在重复,乘上一个系数就可以了。

#include<bits/stdc++.h>
using namespace std;

vector<string> V[11];
long long E[62][62],D[62][62][62],t[62];
string s;
int n;
const long long mod=998244353;

int chk(char x){
	if(x>='a' && x<='z') return x-'a';
	if(x>='A' && x<='Z') return x-'A'+26;
	if(x>='0' && x<='9') return x-'0'+52;
}

int main(){
	scanf("%d",&n);
	int mmax=0;
	for(int i=1;i<=n;i++){
		cin>>s;
		int len=s.length();
		V[len].push_back(s);
		for(int j=0;j<len/2;j++) swap(s[j],s[len-1-j]);
		mmax=max(mmax,len);
		V[len].push_back(s);
	}
	long long tot=0;
	for(int i=3;i<=10;i++){
		if(V[i].size()==0) continue;
		sort(V[i].begin(),V[i].end());
		memset(E,0,sizeof(E));
		E[chk(V[i][0][0])][chk(V[i][0][i-1])]++;
		for(int j=1;j<V[i].size();j++)
			if(V[i][j]!=V[i][j-1]) E[chk(V[i][j][0])][chk(V[i][j][i-1])]++;
		memset(D,0,sizeof(D));
		for(int a=0;a<62;a++)
			for(int b=0;b<62;b++) if(E[a][b])
				for(int c=b;c<62;c++) if(E[a][c])
					for(int d=c;d<62;d++) if(E[a][d])
						D[b][c][d]+=1ll*E[a][b]*E[a][c]%mod*E[a][d]%mod,D[b][c][d]>=mod?D[b][c][d]-=mod:0;
		int tmp=24;
		long long ans=0;
		for(int a=0;a<62;a++){
			t[a]++;tmp/=t[a];
			for(int b=a;b<62;b++){
				t[b]++;tmp/=t[b];
				for(int c=b;c<62;c++){
					t[c]++;tmp/=t[c];
					for(int d=c;d<62;d++){
						t[d]++;tmp/=t[d];
						ans+=1ll*tmp*D[a][b][c]%mod*D[a][b][d]%mod*D[a][c][d]%mod*D[b][c][d]%mod;
						tmp*=t[d];t[d]--;
					}
					tmp*=t[c];t[c]--;
				}
				tmp*=t[b];t[b]--;
			}
			tmp*=t[a];t[a]--;
		}
		tot+=ans;
	}
	printf("%lld\n",tot%mod);
}

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/102710470