首页 > 其他分享 >Luogu P2150 [NOI2015]寿司晚宴

Luogu P2150 [NOI2015]寿司晚宴

时间:2022-10-25 14:02:59浏览次数:96  
标签:const P2150 int Luogu 质数 NOI2015 lim include mod


题目链接:​​传送门​

太难了太难了
题意就是问有多少种分案把一个的排列分配为两组并使组间元素两两互质

首先我们只需要考虑根号内的质因子对答案的影响,因为根号外的因子最多出现一次,可以另外单独考虑
内的素数只有
所以我们可以通过状压来枚举他们所有的情况
但是大于的就要单独考虑了
因为
所以一个数不可能同时包含两个大于的相同质因子
也就是一个小于的数最多有个比大的质因子
那么就可以单独考虑将这个大质数放到哪一组中
下面用来表示将这个大质数放到了组中
更新的时候由于只能由上一位转移过来所以第一维可以直接压掉
就是第一组质数集合为第二组质数集合为的方案数
是全局的答案,是当前这个数的答案,就是~这些数
每次要让这两个数组互相更新
大质因子相同的一块统计答案,会减少额外的复杂度

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <complex>
#include <algorithm>
#include <climits>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define
#define

using namespace std;
typedef long long ll;
struct node {
int s, p;
friend bool operator < (const node a, const node b) {
return a.p < b.p; //让相同的大质数凑起来减少枚举量
}
}e[A];
const int pri[] = {2, 3, 5, 7, 11, 13, 17, 19};
const int lim = (1 << 8);
int n, mod; ll f[A][A], g[A][A][2], ans;

int main(int argc, char const *argv[]) {
cin >> n >> mod;
for (int i = 2; i <= n; i++) {
int t = i;
for (int j = 0; j < 8; j++) {
if (t % pri[j] == 0) {
while (t % pri[j] == 0) t /= pri[j];
e[i].s |= (1 << j); //质因子集合
}
e[i].p = t; //唯一的大质数
}
}
sort(e + 2, e + n + 1); f[0][0] = 1;
for (int i = 2; i <= n; i++) {
if (e[i].p == 1 or e[i].p != e[i - 1].p) //换了大质数
for (int j = 0; j <= lim; j++)
for (int k = 0; k <= lim; k++)
g[j][k][0] = g[j][k][1] = f[j][k]; //要更新当前的g数组
for (int j = lim; j >= 0; j--)
for (int k = lim; k >= 0; k--) { //看是否可以更新,也就是有无交集
if ((e[i].s & k) == 0) g[j | e[i].s][k][1] = (g[j | e[i].s][k][1] + g[j][k][1]) % mod;
if ((e[i].s & j) == 0) g[j][k | e[i].s][0] = (g[j][k | e[i].s][0] + g[j][k][0]) % mod;
}
if (e[i].p == 1 or e[i].p != e[i + 1].p)
for (int j = lim; j >= 0; j--) //把求得的g数组赋给f
for (int k = lim; k >= 0; k--) //最后要减去重复算得的f,因为两个集合都不选的情况算了两遍
f[j][k] = (g[j][k][0] + g[j][k][1] - f[j][k] + mod) % mod;
}
for (int i = 0; i <= lim; i++)
for (int j = 0; j <= lim; j++)
if (!(i & j)) ans = (ans + f[i][j]) % mod;
cout << ans << endl;
}


标签:const,P2150,int,Luogu,质数,NOI2015,lim,include,mod
From: https://blog.51cto.com/lyle/5794670

相关文章

  • Luogu P2515 [HAOI2010]软件安装
    题目链接:​​传送门​​很明显,如果图中有一个环那么这个环上的点必须都要选那我们一开始就直接缩点因为每个物品有价值有重量还有有重量限制所以是很明显的树上背包我......
  • Luogu P4421 [COCI2017-2018#1] Lozinke
    题目链接:​​传送门​​一开始直接AC自动机每个串暴力跳fail显然会T,44分#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<complex>#i......
  • Luogu P3182 [HAOI2016]放棋子
    题目链接:​​传送门​​题目说了每行有一个障碍两个障碍不在同一行也不在同一列那障碍放哪里就没关系了矩阵都不用输入或者这样理解:交换矩阵的某两行对答案是没有影响......
  • Luogu P1772 [ZJOI2006]物流运输
    题目链接:​​传送门​​很麻烦也很难想的一道题数据很小大胆yy详细解释在代码里#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<co......
  • Luogu P4149 [IOI2011]Race
    题目链接:​​传送门​​#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<complex>#include<algorithm>#include<climits>#include<......
  • Luogu P2859 [USACO06FEB]摊位预订Stall Reservations
    题目链接:​​传送门​​很明显的要贪心从左右端点考虑先排序保证单调性每次往后看有没有能接上的单调性才保证了这个往后看的复杂度于是就很好写了/***@Date:2019......
  • Luogu P3488 [POI2009]LYZ-Ice Skates
    题目链接:​​传送门​​号脚的人可以穿大小的鞋设为号脚的人的数量假设选择区间就要满足把提出来即维护一个全局最大子段和就好了#include<iostream>#include<cstdi......
  • Luogu P4105 [HEOI2014]南园满地堆轻絮
    题目链接:​​传送门​​明显的二分简单的check我的没有longlong会炸掉50分#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<comple......
  • Luogu P3313 [SDOI2014]旅行
    题目链接:​​传送门​​动态开点+树剖的模板吧。都很熟的话就挺好写的特别注意在dfs序上修改#include<iostream>#include<cstdio>#include<cstring>#include<cstdli......
  • Luogu P2412 查单词
    题目链接:​​传送门​​做完这个题感觉我是个沙雕在越做越麻烦的道路上一去不复返我真傻,真的(会有大量冗余变量)#include<iostream>#include<cstdio>#include<cstring>......