BZOJ #3746: [POI2015]Czarnoksiężnicy okrągłego stołu 动态规划
转载请注明出处:http://www.cnblogs.com/TSHugh/p/8823423.html
读完题就会发现p=0、1的情况以及n=1、2的情况都可以直接判掉,而p=2的时候也可以直接构造,那么现在需要的就是当p=3且n>=3的时候的做法.
容易想到小数据范围下的dfs,但是这难以优化,于是去思考dp的做法.我的思路一开始是dp弧,后来发现可以直接dp两个链,但是复杂度太大,并不比dfs优秀多少.去看题解,只有Claris写了题解,他是这样写的:
p=3时不考虑1的座位进行DP
可以发现对于i+1的位置安排,我们只关心i-2,i-1,i的相对顺序以及它们的相邻、边界情况
所以设f[i][j][S1][S2]表示已经安排了前i个人的座位,i-2,i-1,i的顺序为j,是否有人在两端点为S1,是否有人相邻为S2的方案数
答案最后再除以n
这样复杂度有点飞…
这并没有使我满意,因为我感觉这在时间、空间、代码各方面的复杂度都是不优秀的.
此时我看到了金策的700+ms做法,而且代码也并不长,这让我意识到此题有更加优秀的做法,于是在搜寻标程失败后去poi官网get了一发题解,然后利用google翻译了一发,得到了一个神奇的做法.
首先,题解里说了一句话,这题实际上是在数哈密顿回路,我思考了一下,好像是这样的……然而,这题的解法和哈密顿回路并没有什么卵关系……
转化一下问题:
I.把所有编号i变为n-i.
II.把环拆开,把原问题变成——求一段序列满足题目限制,且开头一定为0,结尾一定为1/2/3.
这样的话,再对三种结尾判断一下取舍,就能得到最终答案了.
对于现在的问题可以设计dp状态(好神奇的状态啊……):
f[i]:对于一段序列,开头为i,结尾为i+1,且序列中的数字均属于[i,n),此序列满足题目限制的方案数.
g[i]:对于一段序列,开头为i+1,结尾为i,且序列中的数字均属于[i,n),此序列满足题目限制的方案数.
先看dp的转移(好厉害的转移啊……):
先贴一张图(来自波兰题解):
你看这张图,你就会懂得求解方法了,于是得到了一个递推式:f[i]=g[i+1]+g[i+2]+g[i+4]+g[i+5].
同理,也可以得到:g[i]=f[i+1]+f[i+2]+f[i+4]+f[i+5].
但是,上述方法似乎只适用于i<=n-8,所以,对于i>=n-7,我们就可以直接dfs处理了.
(注意判断额外限制条件)
假设三种结尾的方案数分别为ans1、ans2、ans3.
既然知道了dp的转移,那么怎么算三种ans呢?
沿用刚才转移的思路,可以得到(图仍然来自波兰题解):
ans1=f[0];(显然)
ans2=f[1]+f[3]+f[4];(原因见上图)
ans3=f[2]+f[4]+f[5]+g[3]+g[4];(原因见上图)
(注意判断额外限制条件)
所以对于p=3且n>=3的时候,判断一下,若n<=7,直接dfs,否则使用上述方法.
至此,这道题就解决了,时间复杂度为O(n),实现见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
char xB[(<<)+],*xS=xB,*xT=xB;
#define gtc (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
inline void read(int &x){
register char ch=gtc;
for(x=;ch<''||ch>'';ch=gtc);
for(;ch>=''&&ch<='';x=(x<<)+(x<<)+ch-'',ch=gtc);
}
const int N=;
const int Inf=0x3f3f3f3f;
const int P=;
int n,k,p,f[N],g[N];
bool NO[N][],die[N],vf[N],vg[N];
#define no(a,b) (NO[a][(b)+3])
#define ok(a,b) (!no(a,(b)-(a)))
inline int work(){
int i,x,y,ans=;
for(i=;i<=k;++i){
read(x),read(y);
if(std::abs(x-y)<=)no(x,y-x)=true;
}
for(i=;i<=n;++i)
if(i&)f[(i+)>>]=i;
else f[n-(i>>)+]=i;
f[]=f[n],f[n+]=f[];
++ans;
for(i=;i<=n;++i)
if(no(f[i],f[i+]-f[i])){
--ans;break;
}
++ans;
for(i=;i<=n;++i)
if(no(f[i],f[i-]-f[i])){
--ans;break;
}
printf("%d\n",ans);
return ;
}
inline int dfs(int pos,int last,int k,int t,int len){
if(pos==len)return std::abs(t-last)<=&&ok(last,t);
int i,ret=;
for(i=std::max(last-,k+);i<=last+&&i<n;++i)
if((!die[i])&&ok(last,i)){
die[i]=true;
ret+=dfs(pos+,i,k,t,len);
die[i]=false;
}
return ret;
}
inline int D(int s,int k,int t){
die[s]=die[t]=true;
int ret=dfs(,s,k,t,n-k);
die[s]=die[t]=false;
return ret;
}
inline int F(int x);
inline int G(int x);
inline int F(int x){
if(vf[x])return f[x];
vf[x]=true;
if(n-x<=)return f[x]=D(x,x,x+);
int ret=;
if(ok(+x,+x))ret=(ret+G(+x))%P;
if(ok(+x,+x)&&ok(+x,+x))ret=(ret+G(+x))%P;
if(ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x))ret=(ret+G(+x))%P;
if(ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x))ret=(ret+G(+x))%P;
return f[x]=ret;
}
inline int G(int x){
if(vg[x])return g[x];
vg[x]=true;
if(n-x<=)return g[x]=D(x+,x,x);
int ret=;
if(ok(+x,+x))ret=(ret+F(+x))%P;
if(ok(+x,+x)&&ok(+x,+x))ret=(ret+F(+x))%P;
if(ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x))ret=(ret+F(+x))%P;
if(ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x)&&ok(+x,+x))ret=(ret+F(+x))%P;
return g[x]=ret;
}
inline int Work(){
int i,x,y,d=,ans=;
for(i=;i<=k;++i){
read(x),read(y);
x=n-x,y=n-y;
if(std::abs(x-y)<=)no(x,y-x)=true;
}
if(n<=){
if(ok(,))ans=(ans+D(,,))%P;
if(ok(,))ans=(ans+D(,,))%P;
if(n>=&&ok(,))ans=(ans+D(,,))%P;
printf("%d\n",ans);
return ;
}
for(i=n-d;i>d;i-=d)G(i),F(i);/*为了防止爆栈和MLE*/
if(ok(,))ans=(ans+F())%P;
if(ok(,)&&ok(,))ans=(ans+F())%P;
if(ok(,)&&ok(,)&&ok(,)&&ok(,))ans=(ans+F())%P;
if(ok(,)&&ok(,)&&ok(,)&&ok(,)&&ok(,))ans=(ans+F())%P;
if(ok(,)&&ok(,)&&ok(,))ans=(ans+F())%P;
if(ok(,)&&ok(,)&&ok(,)&&ok(,)&&ok(,))ans=(ans+F())%P;
if(ok(,)&&ok(,)&&ok(,)&&ok(,)&&ok(,)&&ok(,))ans=(ans+F())%P;
if(ok(,)&&ok(,)&&ok(,)&&ok(,))ans=(ans+G())%P;
if(ok(,)&&ok(,)&&ok(,)&&ok(,)&&ok(,))ans=(ans+G())%P;
printf("%d\n",ans);
return ;
}
int main(){
//freopen("cza.in","r",stdin);
//freopen("cza.out","w",stdout);
read(n),read(k),read(p);
if(n==)return puts(""),;
if(p==)return puts(""),;
if(n==)return puts(k?"":""),;
if(p==)return puts(""),;
if(p==)return work(),;
return Work(),;
}
Kod
BZOJ #3746: [POI2015]Czarnoksiężnicy okrągłego stołu 动态规划的更多相关文章
- BZOJ3746 : [POI2015]Czarnoksiężnicy okrągłego stołu
NOIP前做了几道POI,现在终于能在BZOJ上提交了… 交上去最后几个点WA,看了数据发现p=0的特判错了… p=0,1时特判 p=2时构造两种情况判断 p=3时不考虑1的座位进行DP 可以发现对于 ...
- BZOJ 4276: [ONTAK2015]Bajtman i Okrągły Robin [线段树优化建边]
4276: [ONTAK2015]Bajtman i Okrągły Robin 题意:\(n \le 5000\)个区间\(l,r\le 5000\),每个区间可以选一个点得到val[i]的价值,每 ...
- BZOJ 4276: [ONTAK2015]Bajtman i Okrągły Robin
最大权值匹配,贪心匈牙利即可. 检查一些人是否能被全部抓住可以采用左端点排序,右端点优先队列处理. By:大奕哥 #include<bits/stdc++.h> using namespa ...
- BZOJ 4276 [ONTAK2015]Bajtman i Okrągły Robin 费用流+线段树优化建图
Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢 ...
- bzoj 4276: [ONTAK2015]Bajtman i Okrągły Robin【线段树+最大费用最大流】
--因为T点忘记还要+n所以选小了所以WA了一次 注意!题目中所给的时间是一边闭一边开的区间,所以读进来之后先l++(或者r--也行) 线段树优化建图,很神.(我记得还有个主席树优化建树的?)首先考虑 ...
- [ONTAK2015]Bajtman i Okrągły Robin
bzoj 4276: [ONTAK2015]Bajtman i Okrągły Robin Time Limit: 40 Sec Memory Limit: 256 MB Description 有 ...
- bzoj 4386: [POI2015]Wycieczki
bzoj 4386: [POI2015]Wycieczki 这题什么素质,爆long long就算了,连int128都爆……最后还是用long double卡过的……而且可能是我本身自带大常数吧,T了 ...
- Bajtman i Okrągły Robin
Bajtman i Okrągły Robin 题目描述 你是一个保安,你发现有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i] ...
- 4276: [ONTAK2015]Bajtman i Okrągły Robin
4276: [ONTAK2015]Bajtman i Okrągły Robin Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 345 Solved ...
随机推荐
- html5新特性localStorage和sessionStorage
HTML5 提供了两种在客户端存储数据的新方法: localStorage: (1)它的生命周期是永久的,关闭页面或浏览器之后localStorage中的数据也不会消失. (2)它的容量大小是5M作用 ...
- katalon系列十一:Katalon Studio在Jenkins持续集成
以下在WIN10上运行正常.安装准备:一.安装Katalon Studio二.安装Jenkins三.获取Katalon命令行运行命令:点击工具栏的‘Build CMD’按钮,选择测试集以及其他选项:选 ...
- Python基本编程题
问题1:仅使用 Python 基本语法,即不使用任何模块,编写 Python 程序计算下列数学表达式的结果并输出,小数点后保留3位. ...
- Raft 一致性协议算法 《In search of an Understandable Consensus Algorithm (Extended Version)》
<In search of an Understandable Consensus Algorithm (Extended Version)> Raft是一种用于管理日志复制的一致性算 ...
- 爬虫2.5-scrapy框架-下载中间件
目录 scrapy框架-下载中间件 scrapy框架-下载中间件 middlewares.py中有两个类,一个是xxSpiderMiddleware类 一个是xxDownloaderMiddlewar ...
- Golang项目开发管理
工具 1. task(项目管理,类似于make) go get -u -v github.com/go-task/task/cmd/task 2. gopm(go依赖管理) go get -u git ...
- eBay推Winit海外仓 鼓励卖家拓展北美市场
[亿邦动力网讯]2月11日消息,日前,跨境电商平台eBay与外贸电商服务商万邑通(Winit)合作,针对平台卖家推出了Winit美国海外仓,鼓励卖家拓展北美市场. 亿邦动力网获悉,Winit美国海外仓 ...
- hbase 修复 hbck
hbase 修复使用hbck 新版本的 hbck 可以修复各种错误,修复选项是: (1)-fix,向下兼容用,被-fixAssignments替代 (2)-fixAssignments,用于修复reg ...
- CSS3 使用 calc() 计算高度 vh px
Viewport viewport:可视窗口,也就是浏览器. vw Viewport宽度, 1vw 等于viewport宽度的1% vh Viewport高度, 1vh 等于view ...
- 王者荣耀交流协会final冲刺第五次scrum会议
成员王超,高远博,冉华,王磊,王玉玲,任思佳,袁玥全部到齐,王磊拍照. master:高远博 2.时间跨度 2017年12月5日 18:00 - 18:31,总计31分钟 3.地点 一食堂二楼沙发座椅 ...


