zoukankan      html  css  js  c++  java
  • bzoj 4199 [NOI2015]寿司晚宴

    Description

    为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴。小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴。

    在晚宴上,主办方为大家提供了 n−1 种不同的寿司,编号 1,2,3,…,n−1,其中第 i 种寿司的美味度为 i+1 (即寿司的美味度为从 2 到 n)。
    现在小 G 和小 W 希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:小 G 品尝的寿司种类中存在一种美味度为 x 的寿司,小 W 品尝的寿司中存在一种美味度为 y 的寿司,而 x 与 y 不互质。
    现在小 G 和小 W 希望统计一共有多少种和谐的品尝寿司的方案(对给定的正整数 p 取模)。注意一个人可以不吃任何寿司。

    Input

    输入文件的第 1 行包含 2 个正整数 n,p,中间用单个空格隔开,表示共有 n 种寿司,最终和谐的方案数要对 p 取模。

    Output

    输出一行包含 1 个整数,表示所求的方案模 p 的结果。

    Sample Input

    3 10000

    Sample Output

    9

    HINT

     2≤n≤500


    0<p≤1000000000

    Source

    这是第二遍码这个题的题解了,第一遍快打完的时候被我菊儿子手贱删掉了

    题目要让两个集合中的所有数互质,那么就是相同的质因子不能位于两个不同的集合中

    所以这个题的限制和突破口其实就是质因子

    我们容易发现选了一个数就是相当与选了这个数的质因子的集合,所以我们需要对每个数进行质因数分解

    但是500以内的质数还是比较多的,我们无法通过比较快捷有效的方法每个质因子是否出现过

    然后我们就需要知道一个很鬼的东西:

    在一个数的所有质因子中最多只有一个会大于sqrt(n);

    证明:一个数可以被分解为几个质因子相乘,且这种分解是唯一的,如果有两个质数大于sqrt(n),那么乘积就会大于n,矛盾

    那么sqrt(500)==22.36,在这里面的质数只有8个{2,3,5,7,9,11,13,17,19}.

    这样一个数小于sqrt(n)的因子就可以用状态压缩来完美判断是否出现,我们还需要对大于sqrt的质因子特殊处理

    用一个结构体来存储一个数

    一是要记录这个数前8个因子的二进制状态:zt,二是记录大于等于sqrt(n)的因子 greatest是多少,如果没有则记为1

    我们把数按照greatest排序那么我们可以把greatest相同的放在一起

    我们易发现greatest相同且不为1的必须捆绑处理:必须是只放入第一个人或者只放入第二个人或者都不放入

    我们讲到现在就可以设状态了

    f[s1][s2]表示全局第一个人选集合s1,第二个人选集合s2的方案数(s1,s2都是表示一个二进制的状态);

    g[0][s1][s2],g[1][s1][s2]是临时由f[s1][s2]赋值,再反过来更新f[s1][s2]

    g[0][s1][s2]表示第一个人选s1,第二个人选s2,且当前这个数由第一个人选的方案

    g[1][s1][s2]则反之

    比如把一个数由第一个人选那么我们首先要判断a[i].zt&s2==0,即该数不会与第二个人的集合s2发生矛盾

    我们易想到到转移方程

    g[0][a[i].zt| s1][s2]+=g[0][s1][s2];

    做一遍DP,直到完整的区间结束后由g[0][s1][s2],g[1][s1][s2]赋值给f[s1][s2],这样会保证这个区间的所有数的选择是一样的,不会分居两个集合

    但由于都不选的算了两次,所以f[i][j]=g[0][s1][s2]+g[1][s1][s2]-f[s1][s2]

    这个题要搞清楚f和g的转化时间,最后统计答案即可

    这样就AC了

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<set>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<ctime>
    #define lson num<<1
    #define rson num<<1|1
    #define int long long
    using namespace std;
    const int MAXS=257;
    const int N=550;
    const int S=255;
    int gi()
    {
    	int x=0,flag=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return x*flag;
    }
    struct data
    {
    	int zt,greatest;
    }a[N];
    int n,mod,f[MAXS][MAXS],g[2][MAXS][MAXS];
    int biao[10]={2,3,5,7,11,13,17,19};
    void pre(){
    	for(int i=2;i<=n;i++) {
            int x=i;
            for(int j=0;j<8;j++) {
                if(x%biao[j]>0) continue;
                a[i].zt|=(1<<j);
                while(x%biao[j]==0) x/=biao[j];
            }
            a[i].greatest=x;
        }
    }
    bool cmp(data a,data b){
    	return  a.greatest<b.greatest;
    }
    void work(){
    	for(int i=2;i<=n;i++){
    		if(i==2||a[i].greatest!=a[i-1].greatest||a[i].greatest==1){
    			memcpy(g[0],f,sizeof(f));
    			memcpy(g[1],f,sizeof(f));
    		}
    		for(int j=S;j>=0;j--)
    			for(int k=S;k>=0;k--){
    				if((j&k)==0){
    					if((a[i].zt&k)==0)
    						g[0][a[i].zt|j][k]+=g[0][j][k],g[0][a[i].zt|j][k]%=mod;
    					if((a[i].zt&j)==0)
    						g[1][j][a[i].zt|k]+=g[1][j][k],g[1][j][a[i].zt|k]%=mod;
    				}
    			}
    		if(n==2||a[i].greatest!=a[i+1].greatest||a[i].greatest==1){
    			for(int j=S;j>=0;j--)
    				for(int k=S;k>=0;k--){
    					if((j&k)==0){
    						f[j][k]=g[0][j][k]+g[1][j][k]-f[j][k];
    					}
    				}
    		}
    	}
    }
    main()
    {
    	n=gi(),mod=gi();
    	pre();
    	sort(a+2,a+1+n,cmp);
    	f[0][0]=1;
    	work();
    	int ans=0;
        for(int i=S;i>=0;i--)
            for(int j=S;j>=0;j--)
                if((i&j)==0)
                    ans+=f[i][j],ans%=mod;
    	while(ans<0) ans+=mod;ans%=mod;
    	printf("%lld",ans);
    }
    
  • 相关阅读:
    prism.js——让网页中的代码更好看
    WebAPI之FormData
    ES6背记手册
    搭建本地的百度脑图
    webpack到底是干什么用的?
    浅拷贝和深拷贝
    vue 中使用 watch 的各种问题
    跳一跳外挂的python实现--OpenCV步步精深
    Opencv基础课必须掌握:滑动条做调色盘 -OpenCV步步精深
    Opencv稍微高级点的鼠标事件-OpenCV步步精深
  • 原文地址:https://www.cnblogs.com/qt666/p/6523439.html
Copyright © 2011-2022 走看看