• test20200523 礼物 和 SPOJ Large Party


    礼物

    情人节就要到了,小Y想要买一份礼物送给自己的女朋友。但是他在买完礼物后发现自己并没有女朋友,所以他决定把礼物送给自己(真可怜)。

    这份礼物其实是一个手环。这个手环上一共有(n)个珠子,而且现在它们看上去都是一样的。

    因为没有人陪着过情人节,小Y觉得特别无聊,于是就一个人宅在家里修炼膜法。最终他习得了一种膜法,可以把他手环上(n)个珠子中的(m)个变成金色的,这样他的手环就会显得非常高端大气上档次。

    但是膜法毕竟都是假的,表面上的光鲜亮丽并不能够长久地存在。因此,手环上被变成金色的最长连续段不能太长,具体地,这个最长长度不能超过小Y心里想的一个阈值(k)

    小Y想要知道他在使用膜法后可能产生的不同手环的方案数。两个手环被认为是不同的,当且仅当它们不能仅通过旋转变得一模一样。也就是说,如果两个手环需要通过翻转才能够一模一样,则我们认为这两个手环是不同的。

    由于答案可能很大,所以小Y只需要你告诉他答案对(998244353)取模后的结果就好了。

    对于100%的测试数据,保证(1leq Tleq 5)(1leq nleq 10^6)(0leq kleq mleq n)

    题解

    显然是Burnside引理题。枚举转了(a)步,那么共有(gcd(a,n))个循环,每个循环长度为(frac{n}{gcd(a,n)})

    (mmod frac{n}{gcd(a,n)} eq 0),显然不动点个数为(0)。否则可以看做长为(gcd(a,n))的环上把(m/frac{n}{gcd(a,n)})个点染成金色,且最长连续段不能超过(k)

    如果(m/frac{n}{gcd(a,n)}=gcd(a,n))的话,说明(n)个点都要被染成金色。只需判断(nleq k)即可。

    否则金色就不可能一直拼接,那么手环的最长金色长度可以看成长为(gcd(a,n))的环上的最长金色长度。于是转化成了子问题:长为(n)的环上,要染(m)个金色,最长金色长度不超过(k)的方案数。

    (n-m)个灰色点之间的距离看成变量(x_1,x_2,dots,x_{n-m}),那么求的就是方程

    [x_1+x_2+dots+x_{n-m}=m\ x_1,x_2,dots,x_{n-m}leq k ]

    的解。每个解的贡献是(x_1+1)

    限制(leq k)直接容斥,贡献(x_1+1)利用期望的线性性拆开计算,(x_1)的贡献利用组合意义。

    时间复杂度(O(sigma_1(n)))

    CO int N=1e6+10;
    int prime[N],num,phi[N];
    vector<int> divs[N];
    int fac[N],inv[N],ifac[N];
    
    IN int C(int n,int m){
    	if(m>n) return 0;
    	return mul(fac[n],mul(ifac[m],ifac[n-m]));
    }
    int calc(int n,int m,int k){ // m<n
    	int ans=0;
    	for(int i=0;i<=n-m and i*(k+1)<=m;++i){
    		int sum=mul(C(n-m,i),C(n-i*(k+1)-1,n-m-1));
    		if(i) sum=add(sum,mul(C(n-m-1,i-1),mul(k+1,C(n-i*(k+1)-1,n-m-1)))); // notice range
    		if(i) sum=add(sum,mul(C(n-m-1,i-1),C(n-i*(k+1)-1,n-m)));
    		sum=add(sum,mul(C(n-m-1,i),C(n-i*(k+1)-1,n-m)));
    		ans=add(ans,i%2==0?sum:mod-sum);
    	}
    	return ans;
    }
    void real_main(){
    	int n=read<int>(),m=read<int>(),k=read<int>();
    	int ans=0;
    	for(int g:divs[n])if(m%(n/g)==0){
    		if(m/(n/g)==g){
    			if(n<=k) ans=mul(ans,phi[n/g]);
    			continue;
    		}
    		ans=add(ans,mul(calc(g,m/(n/g),k),phi[n/g]));
    	}
    	ans=mul(ans,fpow(n,mod-2));
    	printf("%d
    ",ans);
    }
    int main(){
    	freopen("gift.in","r",stdin),freopen("gift.out","w",stdout);
    	phi[1]=1;
    	for(int i=2;i<N;++i){
    		if(!prime[i]){
    			prime[++num]=i;
    			phi[i]=i-1;
    		}
    		for(int j=1;j<=num and i*prime[j]<N;++j){
    			prime[i*prime[j]]=1;
    			if(i%prime[j]==0){
    				phi[i*prime[j]]=phi[i]*prime[j];
    				break;
    			}
    			phi[i*prime[j]]=phi[i]*phi[prime[j]];
    		}
    	}
    	for(int i=1;i<N;++i)for(int j=i;j<N;j+=i)
    		divs[j].push_back(i);
    	fac[0]=fac[1]=1;
    	inv[0]=inv[1]=1;
    	ifac[0]=ifac[1]=1;
    	for(int i=2;i<N;++i){
    		fac[i]=mul(fac[i-1],i);
    		inv[i]=mul(mod-mod/i,inv[mod%i]);
    		ifac[i]=mul(ifac[i-1],inv[i]);
    	}
    	for(int T=read<int>();T--;) real_main();
    	return 0;
    }
    

    Large party

    Irena和Sirup正准备下个周末的Party。为这个Party,他们刚刚买了一个非常大的圆桌。他们想邀请每个人,但他们现在不知道如何分配座次。Irena说当有超过(K)个女孩座位相邻(即这些女孩的座位是连续的,中间没有男孩)的话,她们就会说一整晚的话而不和其他人聊天。

    Sirup没有其他选择,只有同意她。然而,作为一名数学家,他很快地痴迷于所有可能方案。

    题目说明: (N)个人围绕着圆桌坐着,其中一些是男孩,另一些是女孩。你的任务是找出所有合法的方案数,使得不超过(K)个女孩座位是连续的。

    循环同构会被认为是同一种方案。

    对于100%的数据(N,Kleq 2000)

    题解

    https://www.cnblogs.com/ErkkiErkko/p/10067750.html
    https://www.cnblogs.com/suika/p/10363559.html

    (nleq k),则没有不合法的方案。方案数为(2^{gcd(a,n)})

    否则每个循环内一定有一个男生。考虑用DP求出方案数(F(gcd(a,n)))

    (G(i))表示(1)(i)都是男生的序列,中间连续女生不超过(k)个的方案数。用前缀和优化(O(1))转移。

    (F(i))表示长为(i)的循环,连续女生不超过(k)个的方案数。

    [F(i)=sum_{j=0}^{min(k,i)}(j+1)G(i-j)\ ]

    用前缀和优化(O(1))转移。

    总时间复杂度(O(n))

    CO int N=2e3+10;
    int power[N],inv[N];
    int G[N],sum[N][2],F[N];
    
    void real_main(){
    	int n=read<int>(),k=read<int>();
    	if(n<=k) copy(power+1,power+n+1,F+1);
    	else{
    		G[1]=sum[1][0]=sum[1][1]=1;
    		for(int i=2;i<=k+2;++i){
    			G[i]=power[i-2];
    			sum[i][0]=add(sum[i-1][0],G[i]);
    			sum[i][1]=add(sum[i-1][1],mul(G[i],i));
    		}
    		for(int i=k+3;i<=n;++i){
    			G[i]=add(sum[i-1][0],mod-sum[i-k-2][0]);
    			sum[i][0]=add(sum[i-1][0],G[i]);
    			sum[i][1]=add(sum[i-1][1],mul(G[i],i));
    		}
    		for(int i=1;i<=k;++i) F[i]=add(power[i],mod-1);
    		for(int i=k+1;i<=n;++i){
    			F[i]=mul(sum[i][0]+mod-sum[i-k-1][0],i+1);
    			F[i]=add(F[i],mod-add(sum[i][1],mod-sum[i-k-1][1]));
    		}
    	}
    	int ans=0;
    	for(int i=1;i<=n;++i) ans=add(ans,F[gcd(i,n)]);
    	ans=mul(ans,inv[n]);
    	printf("%d
    ",ans);
    }
    int main(){
    	power[0]=1;
    	for(int i=1;i<N;++i) power[i]=mul(power[i-1],2);
    	inv[0]=inv[1]=1;
    	for(int i=2;i<N;++i) inv[i]=mul(mod-mod/i,inv[mod%i]);
    	for(int T=read<int>();T--;) real_main();
    	return 0;
    }
    
  • 相关阅读:
    n!末尾有几个零
    NYOJ 14(会场安排)
    使用dynamic来简化反射实现,并且提高了性能。
    VB.NET 、Java 与 C# 语法对比。
    你不得不使用的XML代码生成器,那就是XmlFactory
    C# 和vb.net事件
    SQL Server 2008中的hierarchyid
    系统架构师基础到企业应用架构客户端/服务器
    Asp.Net在IIS上运行不了,就试下下面方法应该可以你的问题
    为你的博客添加几分色彩
  • 原文地址:https://www.cnblogs.com/autoint/p/12951398.html
Copyright © 2020-2023  润新知