hdu4623:crime 数学优化dp
鞍山热身赛的题,也是去年多校原题
题目大意:
求n个数的排列中满足相邻两个数互质的排列的数量并取模
当时的思路就是状压dp.. dp[i][state] state用二进制记录某个数是否被取走,i 表示当前序列末尾的数字
然后gcd状态转移
可是n是28,算了一下有几亿个状态。。没法做。。
回来之后找了题解发现可以用数学方法优化,于是搞了半天终于ac了
首先在这个问题中:
两个数是否互质只与他们的质因数有关,所以质因数相同的数是等价的,称作此问题的等价类
质因数找到这些等价类,并得到每个类中的数的数量是很容易的。。
所以只需要对这些等价类进行处理,最后对每个等价类再乘以数量的排列数就可以得到答案了。
不过此时有了数量,就不能用二进制状压了,应该采用哈希来状压。
研究了一会发现哈希状压和二进制状压差不多,只不过把基数从(1+1)^n变成了 (num[1]+1)*(num[2]+1)....也是很好理解的
这些状态处理完,发现对于n=28只有 5600000个状态了,等价类数是17 所以复杂度是17*5600000
一交MLE了。由于取模最大30000,把数组改为short,中间结果int防溢出,不爆内存了。
然后时限30s,以为可以过,结果又T了。。
于是又想了一会,发现17,19,23这三个数与其他任意一个数的互质。。所以他们与 1 是等价的
加了这个优化以后复杂度下降到约为 14*1800000
8800ms AC...
代码如下
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int prime[]={,,,,,,,,};
const int np=;
int state[];
int g[][];
int vi[];
int num[];
int base[];
short dp[][];
bool ok[];
int n,m,ns,st;
void ini()
{
scanf("%d%d",&n,&m);
memset(g,,sizeof(g));
memset(vi,,sizeof(vi));
memset(num,,sizeof(num));
ns=;
state[++ns]=;
num[ns]=;
for(int i=;i<=n;i++)
{
st=;
if(ok[i])
{
num[]++;
continue;
}
for(int j=;j<np;j++)
{
if(i%prime[j]==)
{
st|=(<<j);
}
}
if(!vi[st])
{
state[++ns]=st;
num[ns]=;
vi[st]=ns;
}
else
{
num[vi[st]]++;
}
}
for(int i=;i<=ns;i++)
{
for(int j=;j<=ns;j++)
{
if((state[i]&state[j])==)
g[i][j]=;
}
}
base[]=;
st=;
for(int i=;i<=ns;i++)
{
base[i+]=base[i]*(num[i]+);
st+=base[i]*num[i];
}
}
int getnum(int i,int x)
{
int res=(x%base[i+])/(base[i]);
return res;
}
int getstate(int i,int num)
{
return num*base[i];
}
void dfs(int t,int x)
{
if(t==)
{
dp[x][]=;
return ;
}
if(dp[x][t]!=-)
return;
dp[x][t]=;
for(int i=;i<=ns;i++)
{
if(g[x][i]&&getnum(i,t)>=)
{
dfs(t-base[i],i);
dp[x][t]=((int)dp[x][t]+dp[i][t-base[i]])%m;
}
}
return;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
int T;
scanf("%d",&T);
memset(ok,,sizeof(ok));
ok[]=;
ok[]=;
ok[]=;
while(T--)
{
ini();
memset(dp,-,sizeof(dp));
int ans=;
for(int i=;i<=ns;i++)
{
dfs(st-base[i],i);
ans=((int)ans+dp[i][st-base[i]])%m;
}
for(int i=;i<=ns;i++)
{
while(num[i]>)
{
ans=((int)ans*num[i])%m;
num[i]--;
}
}
printf("%d\n",ans);
}
}
hdu4623:crime 数学优化dp的更多相关文章
- 【转】斜率优化DP和四边形不等式优化DP整理
(自己的理解:首先考虑单调队列,不行时考虑斜率,再不行就考虑不等式什么的东西) 当dp的状态转移方程dp[i]的状态i需要从前面(0~i-1)个状态找出最优子决策做转移时 我们常常需要双重循环 (一重 ...
- P2120 [ZJOI2007]仓库建设 斜率优化dp
好题,这题是我理解的第一道斜率优化dp,自然要写一发题解.首先我们要写出普通的表达式,然后先用前缀和优化.然后呢?我们观察发现,x[i]是递增,而我们发现的斜率也是需要是递增的,然后就维护一个单调递增 ...
- 【学习笔记】动态规划—斜率优化DP(超详细)
[学习笔记]动态规划-斜率优化DP(超详细) [前言] 第一次写这么长的文章. 写完后感觉对斜优的理解又加深了一些. 斜优通常与决策单调性同时出现.可以说决策单调性是斜率优化的前提. 斜率优化 \(D ...
- 洛谷P2365/5785 任务安排 题解 斜率优化DP
任务安排1(小数据):https://www.luogu.com.cn/problem/P2365 任务安排2(大数据):https://www.luogu.com.cn/problem/P5785 ...
- bzoj-4518 4518: [Sdoi2016]征途(斜率优化dp)
题目链接: 4518: [Sdoi2016]征途 Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地 ...
- bzoj-1096 1096: [ZJOI2007]仓库建设(斜率优化dp)
题目链接: 1096: [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L ...
- 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)
D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...
- 单调队列优化DP,多重背包
单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...
- [BZOJ3156]防御准备(斜率优化DP)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3156 分析: 简单的斜率优化DP
随机推荐
- Solr4.4.0部署到tomcat上
主要步骤如下: 1.下载solr-4.4.0.tgz 2.解压缩solr-4.4.0.tgz,命令tar -xzvf solr-4.4.0.tgz 3.压缩后进入到solr-4.4.0目录,将 exa ...
- BeanFactory调用getbean()对象
Spring通过资源加载器加载相应的XML文件,使用读取器读取资源加载器中的文件到读取器中,在读取过程中,解析相应的xml文件元素,转化为spring定义的数据结BeanDefinition,把相应的 ...
- javascript 中的location.reload
location.reload()是什么意思 location.reload() 括号内有一个参数 true/false , 为空和false的效果一样. 如果该方法没有规定参数,或者参数是 fals ...
- 关于AppStore上传相关问题
1.电脑本地证书CertificateSigningRequest.certSigningRequest一定要一致(包括开发者证书,尤其是发布证书要一致,否则无法正常上传),此类错误Xcode一般会提 ...
- 对list集合去重操作
import java.util.ArrayList; import java.util.List; //删除集合中重复的数据 public class RemoteTheSameDataInList ...
- js中的call()与apply()
js中的call()函数和apply()函数: 1.主要作用:是用于指定作用域和传参 (1)用于指定作用域 window.color = "red"; var o = { colo ...
- java Date获取 年月日时分秒
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...
- IOS开发之微博的设计与实现
// // main.m // Microblog // #import <Foundation/Foundation.h> #import "Person.h" #i ...
- 通过数组初始化链表的两种方法:指向指针的引用node *&tail和指向指针的指针(二维指针)node **tail
面试高频题:单链表的逆置操作/链表逆序相关文章 点击打开 void init_node(node *tail,char *init_array) 这样声明函数是不正确的,函数的原意是通过数组初始化链表 ...
- Socket 理解
TCP/IP要想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协 ...