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

    题目描述

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

    在晚宴上,主办方为大家提供了 n−1 种不同的寿司,编号 (1,2,3,dots ,n-1)其中第种寿司的美味度为i+1。(即寿司的美味度为从 2 到 n)

    现在小 G 和小 W 希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:小G品尝的寿司种类中存在一种美味度为 x 的寿司,小 W 品尝的寿司中存在一种美味度为 y 的寿司,而 x 与 y 不互质。

    现在小 G 和小 W 希望统计一共有多少种和谐的品尝寿司的方案(对给定的正整数 p 取模)。注意一个人可以不吃任何寿司。

    输入格式

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

    输出格式

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

    输入输出样例

    输入

    3 10000

    输出

    9

    输入

    4 10000

    输出

    21

    输入

    100 100000000

    输出

    3107203

    说明/提示

    【数据范围】
    (n <= 500)

    首先,先明确若不互质也就是他们的质因数集合有交集
    一个暴力
    (n <= 30) 那么可以把所有的质数状压,然后dp即可。
    正解
    但是,(n <= 500) 就会有很多质因数,没法状压,但是发现一个数最多只有一个(>=23)的质因数,那么可以对(<23)的质因数状压,再单独考虑大的质因数。具体的说,可以将所有数按照大质因数(记为Big)排序,对于每一段Big相同的段可以将dp数组赋值给f,g然后再dp,最后再合并回去。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<bitset>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long LL;
    using namespace std;
    #define int long long
    inline int read()
    {
        register int x = 0 , f = 0; register char c = getchar();
        while(c < '0' || c > '9') f |= c == '-' , c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
        return f ? -x : x;
    }
    int n , mod;
    int dp[1 << 8 | 1][1 << 8 | 1] , f[1 << 8 | 1][1 << 8 | 1] , g[1 << 8 | 1][1 << 8 | 1];
    const int prime[] = {2 , 3 , 5 , 7 , 11 , 13 , 17 , 19};
    struct node
    {
    	int S , Big;
    	void Init(int val)
    	{
    		Big = -1; S = 0;
    		for(int i = 0 ; i < 8 ; ++i)
    		{
    			if(val % prime[i] == 0)
    			{
    				S |= 1 << i;
    				while(val % prime[i] == 0) val /= prime[i];
    			}
    		}
    		if(val > 1) Big = val;
    		return ;
    	}
    }s[520];
    
    inline bool cmp(const node &A , const node &B) { return A.Big < B.Big; }
    
    main()
    {
    	n = read(); mod = read();
    	for(int i = 2 ; i <= n ; ++i) s[i-1].Init(i); n--;
    	sort(s + 1 , s + 1 + n , cmp);
    	dp[0][0] = 1;
    	for(int i = 1 ; i <= n ; ++i)
    	{
    		if(s[i].Big == -1)
    		{
    			for(int j = 255 ; ~j ; --j)
    				for(int k = 255 ; ~k ; --k) if((j & k) == 0)
    				{
    					if((k & s[i].S) == 0) (dp[j | s[i].S][k] += dp[j][k]) %= mod;
    					if((j & s[i].S) == 0) (dp[j][k | s[i].S] += dp[j][k]) %= mod;
    				}
    			continue;
    		}
    		if(i == 1 || s[i].Big != s[i-1].Big)
    			memcpy(f , dp , sizeof dp) , memcpy(g , dp , sizeof dp);
    		for(int j = 255 ; ~j ; --j)
    			for(int k = 255 ; ~k ; --k) if((j & k) == 0)
    			{
    				if((k & s[i].S) == 0) (f[j | s[i].S][k] += f[j][k]) %= mod;
    				if((j & s[i].S) == 0) (g[j][k | s[i].S] += g[j][k]) %= mod;
    			}
    		if(i == n || s[i].Big != s[i+1].Big)
    			for(int j = 255 ; ~j ; --j)
    				for(int k = 255 ; ~k ; --k) if((j & k) == 0)
    					dp[j][k] = ((f[j][k] + g[j][k] - dp[j][k]) % mod + mod) % mod;
    	}
    	int ans = 0;
    	for(int i = 0 ; i <= 255 ; ++i)
    		for(int j = 0 ; j <= 255 ; ++j) if((i & j) == 0)
    			(ans += dp[i][j]) %= mod;
    	cout << ans << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    编程微刊第八期文章汇总(2018.8)
    vue踩坑-This dependency was not found
    vue踩坑-This dependency was not found
    百度地图API的使用示例
    详解如何在vue项目中引入饿了么elementUI组件
    vue踩坑- 报错npm ERR! cb() never called!
    2018年九个很受欢迎的vue前端UI框架
    vue踩坑-Error: listen EADDRNOTAVAIL 192.168.1.122:8081
    详解如何在vue项目中引入饿了么elementUI组件
    js学习总结----使用setTimeout实现轮循动画
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12769793.html
Copyright © 2011-2022 走看看