转载请注明出处: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 动态规划的更多相关文章

  1. BZOJ3746 : [POI2015]Czarnoksiężnicy okrągłego stołu

    NOIP前做了几道POI,现在终于能在BZOJ上提交了… 交上去最后几个点WA,看了数据发现p=0的特判错了… p=0,1时特判 p=2时构造两种情况判断 p=3时不考虑1的座位进行DP 可以发现对于 ...

  2. 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]的价值,每 ...

  3. BZOJ 4276: [ONTAK2015]Bajtman i Okrągły Robin

    最大权值匹配,贪心匈牙利即可. 检查一些人是否能被全部抓住可以采用左端点排序,右端点优先队列处理. By:大奕哥 #include<bits/stdc++.h> using namespa ...

  4. 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时间中选出一个时间进行抢劫,并计划抢 ...

  5. bzoj 4276: [ONTAK2015]Bajtman i Okrągły Robin【线段树+最大费用最大流】

    --因为T点忘记还要+n所以选小了所以WA了一次 注意!题目中所给的时间是一边闭一边开的区间,所以读进来之后先l++(或者r--也行) 线段树优化建图,很神.(我记得还有个主席树优化建树的?)首先考虑 ...

  6. [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 有 ...

  7. bzoj 4386: [POI2015]Wycieczki

    bzoj 4386: [POI2015]Wycieczki 这题什么素质,爆long long就算了,连int128都爆……最后还是用long double卡过的……而且可能是我本身自带大常数吧,T了 ...

  8. 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] ...

  9. 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 ...

随机推荐

  1. Python数据可视化的10种技能

    今天我来给你讲讲Python的可视化技术. 如果你想要用Python进行数据分析,就需要在项目初期开始进行探索性的数据分析,这样方便你对数据有一定的了解.其中最直观的就是采用数据可视化技术,这样,数据 ...

  2. 【TCP_协议_socket接口】-jmeter

    1.ip 2.端口号 3.传入参数 4.告诉软件返回  最后以为是什么,不然就会报错 或者无限制的等待  查ascll 码表 启动接口的方法

  3. Beta阶段中间产物

    空天猎功能说明书:https://git.coding.net/liusx0303/Plane.git 空天猎代码控制:https://coding.net/u/MR__Chen/p/SkyHunte ...

  4. RIGHT-BICEP测试第二次程序

    根据Right-BICEP单元测试的方法我对我写的第二次程序进行了测试: 测试一:测试能否控制使用乘除 测试二:测试是否能加括号 测试三:是否可以控制题目输出数量 测试四:能否控制输出方式,选择文件输 ...

  5. Java中的断言assert

    Java陷阱之assert关键字   一.概述   在C和C++语言中都有assert关键,表示断言. 在Java中,同样也有assert关键字,表示断言,用法和含义都差不多.   二.语法   在J ...

  6. WCF RestFull提交数据超出限额解决方法

    最近在使用wcf restfull时出现了超大数据提交出错的问题. 服务端会返回错误:服务器处理请求时遇到错误.有关构造有效服务请求的内容,请参阅服务帮助页.异常消息为“反序列化对象 属于类型 Yes ...

  7. WebService(二)

    使用eclipse开发webservice的服务器端以及客户端的简单实例 1.服务端 在eclipse中像建立一个web项目一样,new->Dynamic Web Project A.建一个需要 ...

  8. Win10 版本情况 201810

  9. Bootstrap-tagsinput标系统使用心得

    最近工作中由于需求使用到了Bootstrap-tagsinput标系统,我的需求是: 1)能够从后台数据库获取标签信息展示到前端页面: 2)能够实现输入标签添加到后台,并ajax刷新页面: 3)能够实 ...

  10. WordPress使用淘宝IP地址库的API显示评论者的位置信息(二)

    1 淘宝IP地址库的接口说明 在上一篇文章<WordPress使用淘宝IP地址库的API显示评论者的位置信息(一)>中,vfhky使用了新浪工具提供的这个IP接口显示博客评论者的位置信息. ...