zoukankan      html  css  js  c++  java
  • Luogu2150 寿司晚宴

    Description

    link

    给定 (n) 求将 (2 o n) 的所有数分成两份,使得两份中的每一对数都互质的方案数,可以有数不在任何一份中

    (nle 500)

    Solution

    不互质就是有共同的因子

    那就看两个人的方案里面统计因子个数然后状压质数吗?

    质数显然是不能被状压的,因为压不动……

    但是一个数必然的构成要不是单独是一个质数,要不必然有一个 (sqrt{500}) 一下的质因子,目测是只有$1 o 19 $ (8)个素数

    啊这里结论没有想到位!!!

    光想到 (sqrt{500})

    Each number could only have one divisor which is greater than (sqrt{500})

    So what we can do is that sorting the number (2 o n) by its greater divisor

    It means that if the two num has the same greater divisor, they can' t be chosen by the same person

    This is the way how we deal it

    吓死我了,我还以为输入不了中文了……又能成了就好……

    下面的 ”段“ 指那些较大质因子相同的数字组成的那个段,每个素数自成一个段

    具体地来说……设一个 (ans_{i,j}) 来统计答案,(f1_{x,y}) 表示在段内的给第一个人统计的方法……(f2_{x,y}) 表示在段内给第二个人统计的方法

    在段开始处理的时候把 (ans) 的值赋给 (f_1,f_2)

    如果 (S&T=0), 那么这种方案合法

    对于段内的每个数字, (calc) 一下 它包含的小质数集合

    能与上的就加

    处理完每个段之后要 (ans_{S_1,S_2}=f1_{S_1,S_2}+f2_{S_1,S_2}-ans_{S_1,S_2})

    这里还得写滚动数组

    我直接反向处理了,感觉相对好写一点

    最后把所有的合法状态一统计就完事了

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define For(i,a,b) for(int i=a;i<=b;++i)
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f;
    	}
    	const int N=510,SZ=1<<8;
    	int n,pri[N],cnt,fl[N],f[SZ][SZ],g[SZ][SZ],ans[SZ][SZ],mod;
    	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    	inline int del(int x,int y){return x-y<0?x-y+mod:x-y;}
    	struct node{
    		int id,val,k;
    		#define k(i) num[i].k
    		#define val(i) num[i].val
    		#define id(i) num[i].id
    		bool operator <(const node &a)const{return val<a.val;}
    	}num[N];
    	inline void calc(int x)
    	{
    		int t=x; id(x)=x;
    		for(int i=1;i<=min(cnt,8ll);++i)
    		{
    			if(x%pri[i]==0) 
    			{
    				while(x%pri[i]==0) x/=pri[i];
    				k(t)|=1<<(i-1);
    			}
    		} if(x>1) val(t)=x; else val(t)=-t; return ;
    	}
    	inline void seive(int x)
    	{
    		For(i,2,x)
    		{
    			if(!fl[i]) pri[++cnt]=i;
    			for(int j=1;j<=cnt&&i*pri[j]<=x;++j)
    			{                           
    				fl[i*pri[j]]=1; 
    				if(i%pri[j]==0) break; 
    			}
    		}
    		for(int i=2;i<=x;++i) calc(i); 
    		return ;
    	}
    	inline int find(int x)
    	{
    		int res=x; while(val(res+1)==val(res)) ++res; 
    		return res;
    	}
    	int s=0,r;
    	inline void work()
    	{
    		For(i,0,s) For(j,0,s) if(!(i&j)) ans[i][j]=del(add(f[i][j],g[i][j]),ans[i][j]);
    		return ;
    	}
    	signed main()
    	{
    		n=read(); mod=read(); seive(n); s=1;
    		for(int i=1;i<=cnt;++i) if(pri[i]<=19) s<<=1; else break;
    		--s;  sort(num+2,num+n+1); 
    		ans[0][0]=1; 
    		for(int i=2;i<=n;++i) 
    		{
    			r=find(i);
    			For(j,0,s) For(k,0,s) f[j][k]=ans[j][k],g[j][k]=ans[j][k];
    			For(j,i,r)
    			{
    				for(int s1=s;s1>=0;--s1)
    				{
    					for(int s2=s;s2>=0;--s2)
    					{
    						if(s1&s2) continue;
    						if((k(j)&s1)==0) f[s1][s2|k(j)]=add(f[s1][s2|k(j)],f[s1][s2]);
    						if((k(j)&s2)==0) g[s1|k(j)][s2]=add(g[s1|k(j)][s2],g[s1][s2]);
    					}
    				} 
    			} i=r; work();
    		} 	
    		int tot=0;
    		For(i,0,s) For(j,0,s) if(!(i&j)) tot=add(tot,ans[i][j]);
    		printf("%lld
    ",tot);
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    

    随想

    唉……最后还是没想到这题的 (idea)

    可能到时候还是沦为 (30pts) 暴力选手了

    积累个经验吧,按说最近没少做数论题呀

    如果出现有质因子不能被状态压缩下来的情况,那么就按照较大质因子排序,然后每段每段处理
    
    细节上的东西必须要注意,毕竟一个字母让100->0的事情太常见了
  • 相关阅读:
    NEC的学习笔记
    MVC过滤器中获取实体类属性值
    Facebook Hack 语言 简介
    6.格式化输出(转)
    ProcessBuilder 和 Runtime(转)
    JAVA I/O使用方法(转)
    java中输出流OutputStream 类应用实例(转)
    InputStream、OutputStream、String的相互转换(转)
    海茶3 らぶデス3 入门经典教程
    天将降大任于斯人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行拂乱其所为,所以动心忍性,增益其所不能
  • 原文地址:https://www.cnblogs.com/yspm/p/13429668.html
Copyright © 2011-2022 走看看