luogu P6570 [NOI Online #3 提高组]优秀子序列 二进制 dp
LINK:P6570 [NOI Online #3 提高组]优秀子序列
Online 2的T3 容易很多 不过出于某种原因(时间不太够 浪了
导致我连暴力的正解都没写.
容易想到 f[i][j]表示前i个数 当前或为j的方案数.
转移很简单 不过复杂度最坏是n*值域的.
只有20 可以把状态降维 可以枚举子集来剪枝 这样就可以卡过40分了.
容易发现当前为0的时候 整体状态要乘2这个可以打一个标记。
这样在开o2的情况下就可以获得70分的好成绩了。
const int MAXN=200010<<1,maxn=1000010;
int n,maxx,m,top;
int a[maxn],phi[MAXN];
int p[MAXN],v[MAXN],mi[maxn];
int f[MAXN];
inline void prepare()
{
m=1;while(m<=maxx)m=m<<1;
phi[1]=1;
rep(2,m,i)
{
if(!v[i])
{
p[++top]=i;
v[i]=i;
phi[i]=i-1;
}
rep(1,top,j)
{
if(m/p[j]<i)break;
v[i*p[j]]=p[j];
if(v[i]==p[j])
{
phi[i*p[j]]=phi[i]*p[j];
break;
}
phi[i*p[j]]=phi[i]*(p[j]-1);
}
}
}
int main()
{
//freopen("sequence.in","r",stdin);
//freopen("sequence.out","w",stdout);
get(n);mi[0]=1;
rep(1,n,i)get(a[i]),maxx=max(maxx,a[i]),mi[i]=(ll)mi[i-1]*2%mod;
f[0]=1;prepare();--m;int flag=0;
rep(1,n,i)
{
if(!a[i]){++flag;continue;}
if(a[i])if(flag){rep(0,m,j)f[j]=(ll)f[j]*mi[flag]%mod;flag=0;}
int ww=a[i]^m;
for(int j=ww;j;j=ww&(j-1))f[j|a[i]]=add(f[j|a[i]],f[j]);
f[a[i]]=add(f[a[i]],f[0]);
}
int ans=0;
rep(0,m,j)ans=(ans+(ll)f[j]*mi[flag]%mod*phi[j+1])%mod;
put(ans);return 0;
}
考虑优化 这个状态转移显然是不可能再优化了。
容易发现 j这个状态 和序列的顺序是无关的。
换句话说 无论序列长什么样子 只要和原来的数集以及出现的次数对上方案数固定。
这样可以直接利用值域来进行dp 脱离n的大小限制.
容易想到 设f[i]表示状态i的方案数。
这里可以刷表可以填表 不过填表比较清晰.
想到枚举一个数字 j 然后 累加上 sum[j]*f[i^j] sum[j]表示j出现的次数.
容易发现这样会计算重复 枚举j/i^j 刚好会重复 实际上 只需要枚举一半即可。
关于证明也很好想 两边方案数对等 所以枚举一边即可。
这样复杂度为3^18/2。
不开o2就能过 令我难过的是 多写了一个mul函数和add函数就会直接T掉。
所以函数的调用也浪费很多时间 这点值得注意 要减小自己的常数.
const int MAXN=200010<<1,maxn=1000010;
int n,maxx,m,top;
int a[MAXN],phi[MAXN];
int p[MAXN],v[MAXN],f[MAXN];
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int mux(int a,int b){return a-b<0?a-b+mod:a-b;}
inline void prepare()
{
m=1;while(m<=maxx)m=m<<1;
phi[1]=1;
rep(2,m,i)
{
if(!v[i])
{
p[++top]=i;
v[i]=i;
phi[i]=i-1;
}
rep(1,top,j)
{
if(m/p[j]<i)break;
v[i*p[j]]=p[j];
if(v[i]==p[j])
{
phi[i*p[j]]=phi[i]*p[j];
break;
}
phi[i*p[j]]=phi[i]*(p[j]-1);
}
}
}
inline int ksm(int b,int p)
{
int cnt=1;
while(p)
{
if(p&1)cnt=mul(cnt,b);
b=mul(b,b);p=p>>1;
}
return cnt;
}
int main()
{
//freopen("1.in","r",stdin);
//freopen("sequence.out","w",stdout);
get(n);
rep(1,n,i){int get(x);++a[x],maxx=max(maxx,x);}
prepare();--m;f[0]=ksm(2,a[0]);
rep(1,m,i)
{
for(int j=i;j>(i^j);j=i&(j-1))
f[i]=(f[i]+(ll)f[i^j]*a[j])%mod;
}
int ans=0;
rep(0,m,j)ans=add(ans,mul(f[j],phi[j+1]));
put(ans);return 0;
}
luogu P6570 [NOI Online #3 提高组]优秀子序列 二进制 dp的更多相关文章
- 洛谷 P6570 - [NOI Online #3 提高组] 优秀子序列(集合幂级数+多项式)
洛谷题面传送门 首先 \(3^n\) 的做法就不多说了,相信对于会状压 dp+会枚举子集的同学来说不算困难(暴论),因此这篇博客将着重讲解 \(2^nn^2\) 的做法. 首先如果我们把每个 \(a_ ...
- [NOI Online 2021 提高组] 积木小赛
思路不说了. 想起来自己打比赛的时候,没睡好.随便写了个\(HASH\),模数开小一半分都没有. 然后学了\(SAM\),发现这个判重不就是个水题. \(SAM\)是字串tire的集合体. 随便\(d ...
- [NOI Online #2 提高组]涂色游戏 题解
题目描述 你有 1020 个格子,它们从 0 开始编号,初始时所有格子都还未染色,现在你按如下规则对它们染色: 编号是 p1 倍数的格子(包括 0号格子,下同)染成红色. 编号是 p2 倍数的格子染成 ...
- NOI Online #2 提高组 游戏
没用二项式反演的菜比. 题目链接 Solution 非平局代表的树上祖先关系是比较好统计,(可以在处理一个点时,考虑用他去匹配他的子树中的东西)而平局的关系比较难统计.我们不妨求出至少 \(k\) 个 ...
- NOI Online #2 提高组 游记
没 NOI Online 1 挂的惨就来写游记吧,不知道为啥 NOI Online 1 民间数据测得 60 分的 T1 最后爆零了... 昏昏沉沉的醒来,吃了早饭,等到 \(8:30\) 进入比赛网页 ...
- NOI Online #3 提高组 T1水壶 题解
题目描述 有 n 个容量无穷大的水壶,它们从 1∼n 编号,初始时 i 号水壶中装有 Ai 单位的水. 你可以进行不超过 k 次操作,每次操作需要选择一个满足 1≤x≤n−1 的编号 x,然后把 x ...
- NOI On Line 提高组题解
(话说其实我想填的是去年CSP的坑...但是貌似有一道题我还不会写咕咕咕... 先写一下这一次的题解吧. T1:序列.题意省略. 两种操作.这种题要先分析部分分 给出了全部都是2操作的子任务. 发现A ...
- NOI Online #3 提高组 游记
考的好就来写游记吧 2020.5.24 星期日 上一天晚上为了班里事物做 PPT 肝到 11:30,这比赛就打打玩玩.第二天醒来有点昏昏沉沉的感觉. 打开题面,一看 T1,好像是个性质极其简单的前缀和 ...
- Luogu P1850 [NOIp2016提高组]换教室 | 期望dp
题目链接 思路: <1>概率与期望期望=情况①的值*情况①的概率+情况②的值*情况②的概率+--+情况n的值*情况n的概率举个例子,抛一个骰子,每一面朝上的概率都是1/6,则这一个骰子落地 ...
随机推荐
- CSS五种方式实现 Footer 置底
页脚置底(Sticky footer)就是让网页的footer部分始终在浏览器窗口的底部.当网页内容足够长以至超出浏览器可视高度时,页脚会随着内容被推到网页底部:但如果网页内容不够长,置底的页脚就会保 ...
- HDU-1051/POJ-1065 Wooden sticks 木棍子(动态规划 LIS 线型动归)
嘤嘤嘤,实习半年多的小蒟蒻的第一篇博客(题解) 英文的: There is a pile of n wooden sticks. The length and weight of each stick ...
- Mister B and PR Shifts,题解
题目链接 分析: 题意很明白,不再多说了,直接分析题目,首先想一想暴力,直接枚举起点,然后求出来,时间复杂度n*n,显然不太好,所以我们考虑换一种方法枚举,当然本质还是枚举,其实你会发现变化i次和i+ ...
- POJ2393贪心
题意:奶牛们收购了一家世界著名的酸奶工厂Yucky Yogurt. 在接下来的 N (1 <= N <= 10,000) 周,牛奶和人工的价格每周会波动,以致于第i周需要花公司 C_i ( ...
- Linux如何用脚本监控Oracle发送警告日志ORA-报错发送邮件
Linux如何用脚本监控Oracle发送警告日志ORA-报错发送邮件 前言 公司有购买的监控软件北塔系统监控,由于购买的版权中只包含了有限台数据库服务器的监控,所以只监控了比较重要的几台服务器. 后边 ...
- Python切图脚本
背景: 时值疫情,作业需要在网上提交.最近老师改变了交作业方式,之前是提交完整的作业图片即可,现在需要将完整的作业图片切分成一题一题的提交,如果手动切分较麻烦,故本人写了个python脚本实现自动切分 ...
- PHP实现多继承
题问php是否支持多继承? 答案:不可以,只支持单继承. 如何实现多继承呢? 答案:可以使用 interface 或 trait 实现 . interface这里我们就不做过多的说明了,它的原理就是一 ...
- 用python批量处理Excel表格,处理结果又快又好,做办公室最靓的那个仔
使用python批量处理Excel数据 让你根据Excel上所有人的身份证号码,提取出公司员工的生日 让你每个月都将公司所有人的考勤数据整理一下 类似这样的格式化的重复操作,你还在每次都使用的 ...
- TCP 和 UDP,哪个更胜一筹
作为 TCP/IP 中两个最具有代表性的传输层协议,TCP 和 UDP 经常被拿出来相互比较.这些协议具体有什么区别,又是什么作用呢? 在 IT 圈混迹多年的小伙伴们,对 TCP 和 UDP 肯定再熟 ...
- 设计模式:proxy模式
目的:为其他对象提供一种代理以控制对这个对象的访问 理解:尽管Decorator的实现部分与代理相似,但Decorator的目的不一样.Decorator为对象添加一个或多个功能,而代理则控制对对象的 ...