zoukankan      html  css  js  c++  java
  • [BZOJ1974][SDOI2010]代码拍卖会[插板法]

    题意

    询问有多少个数位为 (n) 的形如 (11223333444589) 的数位值不下降的数字在(mod p) 的意义下同余 (0)

    $nleq 10^{18} ,pleq 500 $ 。

    分析

    • 考虑普通的状态,矩乘和考虑每种数字选择什么都没法做,要另辟蹊径。

    • 发现这样的数字都可以拆分成1~9个形如 (111111) 的形式,记为 ( m gg)

    • 考虑算出所有此类数字在(mod p) 意义下余数为 (x) 的有多少个。

    • 状态呼之欲出: (f_{i,j,k}) 表示考虑到 ( m gg) 余数为 (i) 的 ,总的余数为 (j) ,已经选择了 (k)( m gg) 的方案总数。

    • 转移枚举 ( m gg) 余数为 (i) 的选择了多少个,注意这类 ( m gg) 的选择是组合而不是排列,考虑插板法算方案。

    • 总时间复杂度为(O(10^2*p^2))

    可重集的排列变组合可以考虑插板法。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define pb push_back
    typedef long long LL;
    inline int gi(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch))	{if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
    	return x*f;
    }
    template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
    template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
    const int N=504,mod=999911659;
    LL st,n,p,rev[N],cnt[N],f[N][N][10],inv[N];
    int pos[N];
    void add(LL &a,LL b){a+=b;if(a>=mod) a-=mod;}
    LL C(LL n,LL m){
    	LL res=1ll;
    	for(LL i=n-m+1;i<=n;++i) res=i%mod*res%mod;
    	for(LL i=2;i<=m;++i) res=res*inv[i]%mod;
    	return res;
    }
    int main(){
    	scanf("%lld%lld",&n,&p);
    	inv[1]=1;
    	for(int i=2;i<=500;++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    	memset(pos,-1,sizeof pos);
    	pos[0]=0,rev[0]=0,cnt[0]=1;LL v=1%p;
    	for(LL i=1;i<=min(n,p);++i){
    		if(pos[v]!=-1){
    			LL len=i-pos[v],a=(n-i+1)/len,b=(n-i+1)%len;
    			st=rev[pos[v]+(b-1+len)%len];
    			for(int j=pos[v];j<i;++j) cnt[rev[j]]+=a+(j-pos[v]+1<=b);
    			break;
    		}else if(i==n) st=v;
    		pos[v]=i,rev[i]=v,cnt[v]++;
    		v=(v*10+1)%p;
    	}
    	rep(k,0,8) f[0][st][k]=C(cnt[0]+k-1,k);
    	
    	rep(i,1,p-1)
    	rep(j,0,p-1)
    	rep(k,0,8){
    		f[i][j][k]=f[i-1][j][k];
    		rep(h,1,k)
    		add(f[i][j][k],f[i-1][((j-h*i)%p+p)%p][k-h]*C(cnt[i]+h-1,h)%mod);
    	}
    	printf("%lld
    ",f[p-1][0][8]);
    	return 0;
    }
    
  • 相关阅读:
    Mysql 权限命令整理大全
    阿里云ECS发送邮件失败
    彻底删除Kafka中的topic
    mysql Slave 启动失败
    mysql双主热备
    mysql 主从笔记
    mysql主从同步的键值冲突问题的解决方法
    python0.2----如何在windows下搭建最简洁的python环境
    内存0.1---内存里数据的表示形式以及进制转换
    python0.1-----pyhon的优缺点,为何学习python
  • 原文地址:https://www.cnblogs.com/yqgAKIOI/p/9818065.html
Copyright © 2011-2022 走看看