题解 [CF1605F] PalindORme

传送门

这世界上为什么会有如此毒瘤的题啊

  • 所以有些计数题注意一下是不是每个非法序列都唯一对应一个合法子序列,也许可以借此DP

每个非法序列唯一对应一个长度为偶数的good subsequence
发现一个事情:令这个good subsequence的或为 \(s\)
则在剩下的序列中至多剩下一个数 \(a\) 满足 \(a\&s=s\)
于是定义best subsequence为一个序列中的good subsequence与这个剩下的数组成的有序集合
可以发现一个非法序列唯一对应一个best subsequence
于是考虑DP,枚举best subseqence长度转移,即

\[cnt\_bad_{i, j} = \sum\limits_{i' = 0}^{i - 1} \sum\limits_{j' = 0}^{j - 1} f(i, j, i', j')\cdot(cnt\_good_{i', j'}) \]

这里 \(f_{i, j, i', j'}\) 就是长为 \(i\),用了恰好 \(j\) 位的序列中的best subseqence长度为 \(i'\),恰好用了 \(j'\) 位的方案数
算这个东西的时候注意只考虑 \(j-j'\) 位的时候要注意选的数是互不相同且严格大于0的
于是可以组合数+容斥算出
换种写法就是

\[\sum\limits_{i' = 0}^{i - 1} \sum\limits_{j' = 0}^{j - 1} f(i, j, i', j')\cdot(cnt\_total_{i', j'} - cnt\_bad_{i', j'}) \]

复杂度 \(O(n^4)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k;
ll dp[N][N], h[10000], fac[N], inv[N], mod, ans;
ll cnt_bad[N][N], cnt_dis_pos[N][N], cnt_total[N][N];
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}
inline ll C(int n, int k) {return n<k?0:fac[n]*inv[k]%mod*inv[n-k]%mod;}
// inline ll C(ll n, ll k) {ll ans=inv[k]; if (n<k) return 0; for (ll i=n-k+1; i<=n; ++i) ans=ans*i%mod; return ans;}
inline ll C2(ll n, ll k) {ll ans=1; for (ll i=n-k+1; i<=n; ++i) ans=ans*i%mod; return ans;}
inline ll f(int i, int j, int i2, int j2) {return C(i, i2)*C(j, j2)%mod*h[j2*(i-i2)]%mod*cnt_dis_pos[i-i2][j-j2]%mod;}

signed main()
{
	n=read(); k=read(); mod=read();
	fac[0]=fac[1]=1; inv[0]=inv[1]=1; h[0]=1;
	for (int i=2; i<N; ++i) fac[i]=fac[i-1]*i%mod;
	for (int i=2; i<N; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for (int i=2; i<N; ++i) inv[i]=inv[i-1]*inv[i]%mod;
	for (int i=1; i<10000; ++i) h[i]=(h[i-1]<<1)%mod;
	for (int i=0; i<=n; ++i) {
		for (int j=0; j<=k; ++j) {
			for (int s=0; s<=j; ++s) {
				cnt_dis_pos[i][j]=(cnt_dis_pos[i][j]+((j-s)&1?-1:1)*C(j, s)*C2(h[s]-1, i))%mod;
				cnt_total[i][j]=(cnt_total[i][j]+((j-s)&1?-1:1)*C(j, s)*h[s*i])%mod;
			}
			// cnt_dis_pos[i][j]=C2(h[j]-1, i);
			// cnt_total[i][j]=h[i*j];
			// for (int s=0; s<j; ++s) {
			// 	cnt_dis_pos[i][j]=(cnt_dis_pos[i][j]-C(j, s)*cnt_dis_pos[i][s])%mod;
			// 	cnt_total[i][j]=(cnt_total[i][j]-C(j, s)*cnt_total[i][s])%mod;
			// }
			// cout<<cnt_total[i][j]<<endl;
		}
	}
	// cout<<g[0][0]<<endl;
	cnt_total[0][0]=1;
	for (int i=1; i<=n; ++i) {
		for (int j=0; j<=k; ++j) {
			for (int i2=0; i2<i; ++i2) {
				if (i==n && i&1 && i2==i-1) continue;
				for (int j2=0; j2<j; ++j2) {
					// cout<<"f: "<<f(i, j, i2, j2)<<endl;
					cnt_bad[i][j]=(cnt_bad[i][j]+f(i, j, i2, j2)*(cnt_total[i2][j2]-cnt_bad[i2][j2]))%mod;
				}
			}
		}
	}
	// for (int i=0; i<=k; ++i) cout<<"dp: "<<g[n][i]-dp[n][i]<<endl;
	for (int i=0; i<=k; ++i) ans=(ans+C(k, i)*(cnt_total[n][i]-cnt_bad[n][i]))%mod;
	// cout<<h[n*k]<<endl;
	// cout<<dp[n][k]<<endl;
	printf("%lld\n", (ans%mod+mod)%mod);
	
	return 0;
}
posted @ 2021-12-08 06:59  Administrator-09  阅读(1)  评论(0编辑  收藏  举报