• BZOJ_4197_[Noi2015]寿司晚宴_状态压缩动态规划


    BZOJ_4197_[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

    考虑状压每个质因子。。。
    500以内的质数有九十多个,但是一些超过$sqrt{n}$ 的质因子在一个数中最多出现一次。
    于是把前$8$ 个质数压成二进制,对每个数求一遍状态和他包含的大质数。
    把含有大质数相同的一起处理。
    设$f[i][j]$ 表示第一个人选的状态为$i$, 第二个人选的状态为$j$的方案数。
    $g[i][j]$表示第一个人不选这个大质数的方案数,$h[i][j]$表示第二个数不选这个大质数的方案数
    让初始$g[i][j]=h[i][j]=f[i][j]$
    转移后$f[i][j]=g[i][j]+h[i][j]-f[i][j]$
    注意枚举顺序
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <stdlib.h>
    using namespace std;
    int mod,f[266][266],g[266][266],h[266][266];
    int mask=255,n;
    int pr[22];
    struct A {
    	int val,lp;
    }a[550];
    bool cmp(const A &x,const A &y){return x.lp<y.lp;}
    int main() {
    	scanf("%d%d",&n,&mod);
    	int i,j,k,l;
    	pr[2]=0; pr[3]=1; pr[5]=2; pr[7]=3; pr[11]=4; pr[13]=5; pr[17]=6; pr[19]=7;
    	for(i=2;i<=n;i++) {
    		int tmp=i;
    		for(j=2;j*j<=tmp;j++) {
    			if(tmp%j==0) {
    				a[i-1].val|=(1<<pr[j]);
    				while(tmp%j==0) tmp/=j;
    			}	
    		}
    		if(tmp!=1) {
    			if(tmp>19) a[i-1].lp=tmp;
    			else a[i-1].val|=(1<<pr[tmp]);
    		}
    	}
    	int lst=1;
    	sort(a+1,a+n,cmp);
    	f[0][0]=1;
    	for(i=1;i<n;i=lst+1) {
    		if(a[i].lp) {
    			while(lst<n-1&&a[lst+1].lp==a[i].lp) lst++;
    			for(j=0;j<=mask;j++) {
    				for(k=0;k<=mask;k++) {
    					g[j][k]=h[j][k]=f[j][k];
    				}
    			}
    			for(j=i;j<=lst;j++) {
    				for(k=mask;k>=0;k--) {
    					for(l=mask;l>=0;l--) {
    						if(!(k&l)&&!(a[j].val&l)) {
    							g[k|a[j].val][l]=(g[k|a[j].val][l]+g[k][l])%mod;
    							h[l][k|a[j].val]=(h[l][k|a[j].val]+h[l][k])%mod;
    						}
    					}
    				}
    			}
    			for(j=0;j<=mask;j++) {
    				for(k=0;k<=mask;k++) {
    					f[j][k]=((g[j][k]+h[j][k]-f[j][k])%mod+mod)%mod;
    				}
    			}
    		}else {
    			lst=i;
    			for(j=0;j<=mask;j++) {
    				for(k=0;k<=mask;k++) {
    					g[j][k]=f[j][k];
    				}
    			}
    			for(j=0;j<=mask;j++) {
    				for(k=0;k<=mask;k++) {
    					if(!(a[i].val&k)&&!(j&k)) {
    						(f[j|a[i].val][k]+=g[j][k])%=mod;
    						(f[k][j|a[i].val]+=g[k][j])%=mod;
    					}
    				}
    			}
    		}
    	}
    	int ans=0;
    	for(i=0;i<=mask;i++) {
    		for(j=0;j<=mask;j++) {
    			if(!(i&j)&&f[i][j]) ans=(ans+f[i][j])%mod;
    		}
    	}
    	printf("%d
    ",ans);
    }
    
     
     
  • 相关阅读:
    HDU 3911 Black And White 分段树 题解
    Haskell 差点儿无痛苦上手指南
    CFileDialog的使用方法简单介绍
    对 dpif_class 结构体的一点认识
    三层架构之基础知识
    五类常见算法小记 (递归与分治,动态规划,贪心,回溯,分支界限法)
    AlertDialog具体解释
    delphi tcp/ip IdTCPServer1实例一
    23种设计模式(15):备忘录模式
    Android APK反编译具体解释(附图)
  • 原文地址:https://www.cnblogs.com/suika/p/8902140.html
Copyright © 2020-2023  润新知