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

    传送门 : 寿司晚宴

    【Description】:

    给定 (n - 1) 个数 (a_i) , (a_i) 满足 (a_i = i + 1) , 将 (n - 1) 个数分成两堆,两堆必须满足互质,求解方案数。

    • 对于 ( ext{30%})数据 满足 (n leq 30)
    • 对于 ( ext{100%}) 数据 满足 (n leq 500)

    【Solution】:

    Part 1

    对于 (30 ext{%}) 的数据 , 我们显然能够想到,我们状压 (G)(W) 选择的质数集。

    方案数合法的充要条件 :

    (G) 所选的集合 (P)(W) 选择 (W) 的集合满足 : (Gin S , W in T , S cap T = phi)
    (S , T) 是两个大质数集。

    我们发现 (n leq 30) 的时候,最多只有 (10) 个 质数。

    为了表示整个局面和下一步的转移,我们设 (f_{i,G,W}) 为 选完 (i) 这个寿司,(G) 选择的质数集, (W) 选择的质数集 为 (G , W) ,显然我们对于状态转移,就是这个寿司是选择,就有状态转移 :

    [{f_{i , G | P_i , W} += f_{i - 1 , G , W} }, [P_i ext{&} W = 0] ]

    [f_{i , G , W|P_i} += f_{i - 1 , G , W} , [P_i ext{&}W = 0] ]

    (P_i) 则是代表第 (i) 个寿司的美味度的质因数集。

    [Then we can get 30 points . ]

    Part 2 , 3

    (n leq 200) 的时候,想不出来和 (nleq 500) 有什么不一样的做法。

    Part 4

    (n leq 500) 时 , 显然状压 (500) 以内的质因子集是不大现实,(500) 以内的质数个数是 (95) 个来着,状压个锤子 。

    有一个结论可能会帮你完成该题

    对于一个数 (n) 最多有一个 > (sqrt n) 的质因子。

    那么我们就能够直接取出这一个质因子即可。 设为 (big) ,其他我们设为 (small)(sqrt 500) 大概取 (22) ,所以 我们求解 (small) 的时候,只需要将 (22) 以内的质数搞一下分解就好。

    所有 (big) 相同的数显然只能放在一个集合中,所以按照 (big) 的大小排序,这样就可以把所有 (big) 相同的数放在一起算 。

    在计算 (big) 相同的时候,我们发现,就和 (30 opts) 是一样的,我们设 (f_1[P][W] ,f_2[P][W]) 去转移 (30 opts) 的状态转移 。

    小小的容斥原理 (f_{P,W}) 加了两遍

    (f_{P,W} = f_1[P][W] + f_2[P][W] - f[P][W]) , 。

    最后取答案 (ans = sum_{P}sum_{W} f_{P,W})

    【Code】

    /*
    Author : Zmonarch
    知识点 :代码实现看的第一篇题解。
    */
    #include <bits/stdc++.h>
    #define int long long
    #define qwq register
    #define qaq inline
    #define inf 2147483647
    using namespace std ;
    const int kmaxn = 550 ;
    const int kmod = 1e9 + 7 ;
    const int eps = 1e-6 ;
    const int num[] = {0 , 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19} ; 
    inline int read() {
    	int x = 0 , f = 1 ; char ch = getchar() ;
    	while(!isdigit(ch)) {if(ch == '-') f = - 1 ; ch = getchar() ;}
    	while( isdigit(ch)) {x = x * 10 + ch - '0' ; ch = getchar() ;}
    	return x * f ;
    }
    int n , mod , ans ; 
    int f[kmaxn][kmaxn] , f1[kmaxn][kmaxn] , f2[kmaxn][kmaxn] ; 
    struct node 
    {
    	int S = 0 , big , val ; //质数集合 , 大质数
    	void init()  
    	{
    		int tmp = val ; big = 0 ;
    		for(int i = 1 ; i <= 8 ; i++) //分解质因数 	
    		{
    			if(tmp % num[i]) continue ; 
    			S |= (1 << (i - 1)) ;  
    			while((tmp % num[i]) == 0) tmp /= num[i] ;  
    		}
    		if(tmp != 1) big = tmp ; 
    	}
    }a[kmaxn] ; 
    inline bool cmp(node a , node b) {return a.big < b.big ;} 
    signed main()
    {
    	n = read() , mod = read() ; 
    	for(qwq int i = 2 ; i <= n ; i++) a[i - 1].val = i , a[i - 1].init() ; 
    	std::sort(a + 1 , a + n , cmp) ;f[0][0] = 1 ; 
    	for(qwq int i = 1 ; i <= n - 1 ; i++)
    	{
    		if((i == 1) || (a[i].big != a[i - 1].big) || (!a[i].big)) 
    		{
    			memcpy(f1 , f , sizeof(f1)) ; 
    			memcpy(f2 , f , sizeof(f2)) ; 
    		}
    		for(int j=255; j>=0; j--) 
    		  for(int k=255; k>=0; k--) 
    		  {
    		  	if(j & k) continue ; 
    		  	if(!(a[i].S & j)) f2[j][k | a[i].S] = (f2[j][k | a[i].S] + f2[j][k]) % mod ; 
    		  	if(!(a[i].S & k)) f1[j | a[i].S][k] = (f1[j | a[i].S][k] + f1[j][k]) % mod;
    		  }
    		if((i == n - 1) || (a[i].big != a[i + 1].big) || (!a[i].big))
    		{
    			for(int j=0; j<=255; j++) 
    			 for(int k=0; k<=255; k++) 
    			 {
    			  	if(j & k) continue ; 
    			  	f[j][k] = ( (f1[j][k] + f2[j][k] ) % mod - f[j][k] + mod) % mod ;
    			 }
    		} 
    	}
    	ans = 0 ; 
    	for(int j=0; j<=255; j++) 
    	 for(int k=0; k<=255; k++) 
    	  if(!(j & k)) ans = (ans + f[j][k]) % mod ;
    	printf("%lld
    " , ans) ; 
    	return 0 ;
    }
    
  • 相关阅读:
    WinForm 自定义控件 学习笔记三
    FtpWebRequest相关
    delegate学习笔记1
    C#操作XML
    WinForm 非客户区相关
    WinForm 自定义控件 学习笔记二
    POJ1061 青蛙的约会(扩展欧几里得)
    aaaaaaa……aaa(n个)%p的值 (矩阵快速幂)
    POJ3735 Training little cats(矩阵快速幂)
    数据库日志文件太大的解决方法及原理
  • 原文地址:https://www.cnblogs.com/Zmonarch/p/14858753.html
Copyright © 2011-2022 走看看