CSP模拟50联测12

数据比较水,大家随便切

#

肯定是能合并就合并,然后就可以维护一个栈,扫到一个元素判断栈顶元素与这个元素 gcd 不为 1 就可以直接合并,最后看栈内元素个数。

但是用 __int128 未必可以存的下,因此可以获得 70 分好成绩。

考虑 700 的质数有125个,每个数存一下有哪些质因子,用 __int128bitset 可过。

#

行与行,列与列,行与列是独立的,所以分开考虑。

考虑一行LR。

fi,j,gi,j 表示前 i 个还有 j 条R狗没有匹配的方案数,权值和,考虑转移:

1.如果当前不选 :

fi,j=fi1,j

gi,j=gi1,j

2.如果当前是L并且选:(可以选择 j 中的任意一条)

fi,j1=fi1,j×j

gi,j1=gi1,j×j+fi1,j×j×ai

3.如果当前是R并且选:

fi,j+1=fi1,j

gi,j+1=gi1,j+fi1,j×ai

最后将算出来的方案数相乘就是总方案数,每一个权值和要排除自己的方案数。

点击查看代码
#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;
}

#

计算 i=1kai=n 的方案数 g(n),用一个容斥:

g(n)=i=0k(1)i(ki)(n(x+1)i+k1k1)

就是钦定有 i 个是 x+1 的,后面是一个隔板法,将 n(x1)i 拆成一堆 1,因为要分成 k 个数,所以加入 k11,从中选 k1 个一作为板,每两个板之间的一的个数为数的大小,这是没有限制的,数可以 x+1

对于容斥,我的理解是:

|i=1mAi|=|S||Ai|+|AiAj|+(1)m|i=1mAi|

Ai 看作第 i 个数 x+1

答案就是:

对于数位dp,dpa+b=f(i)ia+b

考虑这一位为 x,则变为

f(i)×f(x)×(i+x×10now)a+b

将二项式拆开

f(i)×f(x)×k=0a+b(a+bk)ik(x×10now)a+bk

k=b 时,得到:

f(i)×f(x)×(a+bb)ib(x×10now)a

合并一下

(a+ba)f(x)(x×10now)adp(b)


预处理 cj,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;
}

#

求教教

作者:bloss

出处:https://www.cnblogs.com/jinjiaqioi/p/17743573.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   _bloss  阅读(205)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu