转载请注明出处: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. 个人安装ss的一个记录

    在ubuntu16.04安装ss服务.由于lantern最近极其不稳定(我还花钱的qaq),经常断联以至于几乎废了,莫得办法,只好花钱搭一个了orz...呵,贫穷.... 安装shadowsocks ...

  2. IDEA 破解图文教程 - 2018.9 更

    你好!这里是你要找的 IDEA 破解方法 目录     一.前言    二.IDEA 安装         2.1 下载IDEA 旗舰版         2.2 开始安装         2.3 自定 ...

  3. MongoDB开启权限认证

      MongoDB默认安装完后,如果在配置文件中没有加上auth = true,是没有用户权限认证的,这样对于一个数据库来说是相对不安全的,尤其是在外网的情况下. 接下来是配置权限的过程: //切入到 ...

  4. Open vSwitch for CentOS

    原文发表于cu:2016-06-02 本文属于重发,ovs当前的安装方式可能略有不同. 参考文档: 官方文档: http://openvswitch.org/support/dist-docs-2.5 ...

  5. linux主机上,UnixBench性能测试工具使用

    1,下载  wget http://soft.laozuo.org/scripts/UnixBench5.1.3.tgz [root@VM_0_15_centos test]# [root@VM_0_ ...

  6. 当Kubernets遇上阿里云 -之七层负载均衡(一).

    我们知道Kubernetes的service只能实现基于4层的负载均衡,无法提供7层之上的许多特性,诸如基于URL的负载均衡,SSL支持,三方授权等等:Ingress可以实现七层负载均衡的许多功能,唯 ...

  7. Python 代码调试技巧

    使用 pdb 进行调试 pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点.单步调试.进入函数调试.查看当前代码.查看栈片段.动态改变变 ...

  8. JS 操作 checkbox(cc角色管理等)

    1.获取选中的权限的个数 var size=$("input[name='privileges']:checked").size();

  9. 《JavaScript》JS中的常用方法attr(),splice()

    1.jquery中用attr()方法来获取和设置元素属性,attr是attribute(属性)的缩写,在jQuery DOM操作中会经常用到attr(),attr()有4个表达式. attr(属性名) ...

  10. selenium Object Page 设计模式理解及实现!

    Page Object模式是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,其中包含页面中需要测试的元素(按钮,输入框,标题 等),这样在Selenium测试页面中可以通 ...