CSP模拟50联测12
数据比较水,大家随便切
菜
肯定是能合并就合并,然后就可以维护一个栈,扫到一个元素判断栈顶元素与这个元素 gcd 不为 \(1\) 就可以直接合并,最后看栈内元素个数。
但是用 __int128 未必可以存的下,因此可以获得 \(70\) 分好成绩。
考虑 \(\le700\) 的质数有125个,每个数存一下有哪些质因子,用 __int128 或 bitset 可过。
狗
行与行,列与列,行与列是独立的,所以分开考虑。
考虑一行LR。
设 \(f_{i,j},g_{i,j}\) 表示前 \(i\) 个还有 \(j\) 条R狗没有匹配的方案数,权值和,考虑转移:
1.如果当前不选 :
\[f_{i,j}=f_{i-1,j}
\]
\[g_{i,j}=g_{i-1,j}
\]
2.如果当前是L并且选:(可以选择 \(j\) 中的任意一条)
\[f_{i,j-1}=f_{i-1,j} \times j
\]
\[g_{i,j-1}=g_{i-1,j} \times j + f_{i-1,j} \times j \times a_{i}
\]
3.如果当前是R并且选:
\[f_{i,j+1}=f_{i-1,j}
\]
\[g_{i,j+1}=g_{i-1,j}+f_{i-1,j} \times a_i
\]
最后将算出来的方案数相乘就是总方案数,每一个权值和要排除自己的方案数。
点击查看代码
#include<bits/stdc++.h>
#define mod 998244353LL
#define N 502
using namespace std;
string s[N];
char c[N];
int n,m,ans,a[N],b[N][N],f[N][N],g[N][N],p[N<<1],q[N<<1],cnt;
void solve(){
	memset(f,0,sizeof f);
	memset(g,0,sizeof g);
	f[0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=0;j<=n;j++){
			f[i][j]=(f[i][j]+f[i-1][j])%mod;
			g[i][j]=(g[i][j]+g[i-1][j])%mod;
			if(c[i]=='L' || c[i]=='U'){
				if(j){
					f[i][j-1]=(f[i][j-1]+1ll*f[i-1][j]*j%mod)%mod;
					g[i][j-1]=((g[i][j-1]+1ll*g[i-1][j]*j%mod)%mod+
					1ll*f[i-1][j]*j%mod*a[i]%mod)%mod;
				}
			}
			else{
				f[i][j+1]=(f[i][j+1]+f[i-1][j])%mod;
				g[i][j+1]=((g[i][j+1]+g[i-1][j])%mod+1ll*f[i-1][j]*a[i]%mod)%mod;
			}
		}
	p[++cnt]=g[n][0];
	q[cnt]=f[n][0];
}
int main(){
	cin>>m;
	int i,j,k;
	for(i=0;i<m;i++) cin>>s[i];
	for(i=0;i<m;i++) for(j=0;j<m;j++) cin>>b[i][j];
	for(i=0;i<m;i++){
		n=0;
		for(j=0;j<m;j++)
			if(s[i][j]=='L' || s[i][j]=='R'){
				c[++n]=s[i][j];
				a[n]=b[i][j];
			}
		if(n) solve();
		n=0;
		for(j=0;j<m;j++)
			if(s[j][i]=='U' || s[j][i]=='D'){
				c[++n]=s[j][i];
				a[n]=b[j][i];
			}
		if(n) solve();
	}
	for(i=1;i<=cnt;i++){
		k=p[i];
		for(j=1;j<=cnt;j++) if(i!=j) k=(1LL*k*q[j])%mod;
		ans=(ans+k)%mod;
	}
	cout<<ans<<endl;
	return 0;
}
可
计算 \(\sum_{i=1}^{k}a_i=n\) 的方案数 \(g(n)\),用一个容斥:
\[g(n)=\sum_{i=0}^{k}(-1)^i \binom {k}{i} \binom{n-(x+1)i+k-1}{k-1}
\]
就是钦定有 \(i\) 个是 \(\ge x+1\) 的,后面是一个隔板法,将 \(n-(x-1)i\) 拆成一堆 \(1\),因为要分成 \(k\) 个数,所以加入 \(k-1\) 个 \(1\),从中选 \(k-1\) 个一作为板,每两个板之间的一的个数为数的大小,这是没有限制的,数可以 \(\le x+1\)。
对于容斥,我的理解是:
\[\left|\bigcap_{i=1}^m \overline{A_i}\right|=|S|-\sum|A_i|+\sum|A_i \cap A_j| -\cdots+(-1)^m\left|\bigcap_{i=1}^m {A_i}\right|
\]
将 \(A_i\) 看作第 \(i\) 个数 \(\ge x+1\)。
答案就是:

对于数位dp,\(dp_{a+b}=\sum f(i)i^{a+b}\)
考虑这一位为 \(x\),则变为
\[\sum f(i) \times f(x) \times (i+x \times 10^{now})^{a+b}
\]
将二项式拆开
\[\sum f(i) \times f(x) \times \sum_{k=0}^{a+b} \binom{a+b}{k}i^k(x \times 10^{now})^{a+b-k}
\]
当 \(k=b\) 时,得到:
\[\sum f(i) \times f(x) \times \binom{a+b}{b}i^b(x \times 10^{now})^{a}
\]
合并一下
\[\sum \binom{a+b}{a} f(x) (x \times 10^{now})^a dp(b)
\]

预处理 \(c_{j,l}\) 可以提前取模
粘的std
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p = 1e9 + 7;
int n,k,b[10015],a[10015],B[10015],ten[10015],C[25][25];
int c[15][25],d[15][25],h[25],ans;
ll f[25],g[25],F[25],G[25];
char st[10015];
inline void inc(int &x,int y){(x+=y)>=p?x-=p:0;}//快速 加 + 取模 
inline int solve(){
	memset(f,0,sizeof(f));
	memset(g,0,sizeof(g));
	f[0]=1;
	int num=0,res=0;
	for(int K=n,A;K>=0;--K){//数位dp 
		A=a[K];
		for(int i=9,X,Y;i>=0;--i){//枚举当前位的数字 
			X=max(i,1),Y=(ll)i*ten[K]%p;
			c[i][0]=d[i][0]=X;
			inc(d[i][0],d[i+1][0]);
			for(int j=1;j<=k-1;++j){
				c[i][j]=d[i][j]=(ll)c[i][j-1]*Y%p;
				inc(d[i][j],d[i+1][j]);
			}
		}
		for(int i=k-1;i>=0;--i){
			g[i]=g[i]*d[0][0]%p;
			for(int j=0;j<=i;++j)
				F[j]=f[j]*C[i][j]%p,G[j]=g[j]*C[i][j]%p;
			for(int j=0;j<=i;++j){
				if(j<i)g[i]+=G[j]*d[0][i-j];
				g[i]+=F[j]*d[A+1][i-j];
				if((j&3)==3)g[i]%=p;
			}
			f[i]*=c[A][0];
			for(int j=0;j<i;++j){
				f[i]+=F[j]*c[A][i-j];
				if((j&7)==7)f[i]%=p;
			}
			f[i]%=p,g[i]%=p;
		}
		num=(num+(ll)A*ten[K])%p;
	}
	memset(h,0,sizeof(h));
	h[0]=1;
	for(int i=1;i<=k-1;++i)
		for(int j=k-2;j>=0;--j)
			inc(h[j+1],h[j]),h[j]=(ll)h[j]*(i-num+p)%p;
	for(int i=0;i<=k-1;++i)
		res=(res+(ll)h[i]*(f[i]+g[i]))%p;
	return res;
}
inline int qpow(int a,int b){
	int res=1;
	while(b){
		if(b&1)res=(ll)res*a%p;
		if(b>>=1)a=(ll)a*a%p;
	}
	return res;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0); 
	cin >> k >> st + 1;
	n=strlen(st+1);
	for(int i=0;i<n;++i)b[i]=st[n-i]^48;// b 就是 x 
	n+=3;
	// for(int i=0;i<=n;++i){//B = kx 
	// 	// cout<<b[i];
	// 	B[i]+=b[i]*k;
	// 	B[i+1]+=B[i]%10,B[i]/=10;
	// }
	// cout<<endl;
	// for(int i=0;i<=n+1;i++){
	// 	cout<<B[i];
	// }
	// cout<<endl;
	++b[0];//x++; 
	for(int i=0;i<=n;++i)//处理进位 
		b[i+1]+=b[i]/10,b[i]%=10;
	ten[0]=1;
	for(int i=1;i<=n;++i)//十进制 ,1,10,100,,,, 
		ten[i]=ten[i-1]*10ll%p;
	for(int i=0;i<=k;++i){
		for(int j=1;j<=i;++j)
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%p;//组合数 
		C[i][0]=1;
	}
	for(int i=0;i<=k;++i){
		ans=(ans+(i&1?-1ll:1ll)*C[k][i]*solve())%p;//容斥 
		for(int j=0;j<=n;++j){
			a[j]+=b[j];
			a[j+1]+=a[j]/10,a[j]%=10;
		}
	}
	for(int i=1;i<=k-1;++i)
		ans=(ll)ans*qpow(i,p-2)%p;
	cout << (ans + p) % p << "\n";
	return 0;
}
爱
求教教

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号