转载请注明出处: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[(1<<15)+10],*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=0;ch<'0'||ch>'9';ch=gtc);for(;ch>='0'&&ch<='9';x=(x<<1)+(x<<3)+ch-'0',ch=gtc);
}
const int N=1000010;
const int Inf=0x3f3f3f3f;
const int P=1000000007;
int n,k,p,f[N],g[N];
bool NO[N][7],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=0;for(i=1;i<=k;++i){read(x),read(y);if(std::abs(x-y)<=3)no(x,y-x)=true;}for(i=1;i<=n;++i)if(i&1)f[(i+1)>>1]=i;else f[n-(i>>1)+1]=i;f[0]=f[n],f[n+1]=f[1];++ans;for(i=1;i<=n;++i)if(no(f[i],f[i+1]-f[i])){--ans;break;}++ans;for(i=1;i<=n;++i)if(no(f[i],f[i-1]-f[i])){--ans;break;}printf("%d\n",ans);return 0;
}
inline int dfs(int pos,int last,int k,int t,int len){if(pos==len)return std::abs(t-last)<=3&&ok(last,t);int i,ret=0;for(i=std::max(last-3,k+1);i<=last+3&&i<n;++i)if((!die[i])&&ok(last,i)){die[i]=true;ret+=dfs(pos+1,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(2,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<=7)return f[x]=D(x,x,x+1);int ret=0;if(ok(0+x,2+x))ret=(ret+G(1+x))%P;if(ok(0+x,3+x)&&ok(2+x,1+x))ret=(ret+G(2+x))%P;if(ok(0+x,3+x)&&ok(3+x,2+x)&&ok(2+x,5+x)&&ok(4+x,1+x))ret=(ret+G(4+x))%P;if(ok(0+x,3+x)&&ok(3+x,6+x)&&ok(5+x,2+x)&&ok(2+x,4+x)&&ok(4+x,1+x))ret=(ret+G(5+x))%P;return f[x]=ret;
}
inline int G(int x){if(vg[x])return g[x];vg[x]=true;if(n-x<=7)return g[x]=D(x+1,x,x);int ret=0;if(ok(2+x,0+x))ret=(ret+F(1+x))%P;if(ok(1+x,2+x)&&ok(3+x,0+x))ret=(ret+F(2+x))%P;if(ok(1+x,4+x)&&ok(5+x,2+x)&&ok(2+x,3+x)&&ok(3+x,0+x))ret=(ret+F(4+x))%P;if(ok(1+x,4+x)&&ok(4+x,2+x)&&ok(2+x,5+x)&&ok(6+x,3+x)&&ok(3+x,0+x))ret=(ret+F(5+x))%P;return g[x]=ret;
}
inline int Work(){int i,x,y,d=100000,ans=0;for(i=1;i<=k;++i){read(x),read(y);x=n-x,y=n-y;if(std::abs(x-y)<=3)no(x,y-x)=true;}if(n<=7){if(ok(1,0))ans=(ans+D(0,0,1))%P;if(ok(2,0))ans=(ans+D(0,0,2))%P;if(n>=4&&ok(3,0))ans=(ans+D(0,0,3))%P;printf("%d\n",ans);return 0;}for(i=n-d;i>d;i-=d)G(i),F(i);/*为了防止爆栈和MLE*/if(ok(1,0))ans=(ans+F(0))%P;if(ok(2,0)&&ok(0,1))ans=(ans+F(1))%P;if(ok(4,1)&&ok(1,2)&&ok(2,0)&&ok(0,3))ans=(ans+F(3))%P;if(ok(5,2)&&ok(2,0)&&ok(0,3)&&ok(3,1)&&ok(1,4))ans=(ans+F(4))%P;if(ok(3,0)&&ok(0,1)&&ok(1,2))ans=(ans+F(2))%P;if(ok(5,2)&&ok(2,3)&&ok(3,0)&&ok(0,1)&&ok(1,4))ans=(ans+F(4))%P;if(ok(6,3)&&ok(3,0)&&ok(0,1)&&ok(1,4)&&ok(4,2)&&ok(2,5))ans=(ans+F(5))%P;if(ok(3,0)&&ok(0,2)&&ok(2,1)&&ok(1,4))ans=(ans+G(3))%P;if(ok(4,1)&&ok(1,3)&&ok(3,0)&&ok(0,2)&&ok(2,5))ans=(ans+G(4))%P;printf("%d\n",ans);return 0;
}
int main(){//freopen("cza.in","r",stdin);//freopen("cza.out","w",stdout);
  read(n),read(k),read(p);if(n==1)return puts("1"),0;if(p==0)return puts("0"),0;if(n==2)return puts(k?"0":"1"),0;if(p==1)return puts("0"),0;if(p==2)return work(),0;return Work(),0;
}

Kod

转载于:https://www.cnblogs.com/TSHugh/p/8823423.html

BZOJ #3746: [POI2015]Czarnoksiężnicy okrągłego stołu 动态规划相关推荐

  1. BZOJ 3747 POI2015 Kinoman 段树

    标题效果:有m点,每个点都有一个权值.现在我们有这个m为点的长度n该序列,寻求区间,它仅出现一次在正确的点区间内值和最大 想了很久,甚至神标题,奔说是水的问题--我醉了 枚举左点 对于每个请求留点右键 ...

  2. bzoj 3750: [POI2015]Pieczęć(模拟)

    3750: [POI2015]Pieczęć Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 309  Solved: 171 [Submit][Sta ...

  3. bzoj 3749: [POI2015]Łasuchy

    3749: [POI2015]Łasuchy Time Limit: 10 Sec  Memory Limit: 64 MBSec  Special Judge Submit: 355  Solved ...

  4. [Luogu P3597] [BZOJ 4386] [POI2015]WYC

    洛谷传送门 BZOJ传送门 题目描述 给定一张nnn个点mmm条边的带权有向图,每条边的边权只可能是111,222,333中的一种.将所有可能的路径按路径长度排序,请输出第kkk小的路径的长度,注意路 ...

  5. @bzoj - 4384@ [POI2015] Trzy wieże

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个长度为 n 的仅包含'B'.'C'.'S'三种字符的字符 ...

  6. bzoj 3747: [POI2015]Kinoman

    (颓废扒题解2333) 给颜色的下一个出现位置记录一下,然后每次只有第一个颜色的出现位置和下一个出现位置之间会产生这种颜色的价值,所以用线段树维护一下区间. 那么现在就只需要把整个的数列从1-> ...

  7. Hdu-6249 2017CCPC-Final G.Alice’s Stamps 动态规划

    题面 题意:给你n个集合,每个集合有L到R这些种类的邮票,让你选择其中的K个集合,使得最后选择的邮票种类尽可能多,N,L,R都<=2000 题解:容易乱想到网络流,可是再细想一下就会发现处理不了 ...

  8. codeforces G - Almost Increasing Array 动态规划、动态开点线段树

    题意 给出一个序列,允许删除一个元素,并将任意元素的值修改为任意整数,问最少修改多少个元素使得序列变成严格单调递增的序列? 题解 这道题目很具有启发性: 不考虑删除元素,原数列各个数值减去他们下标得到 ...

  9. mysql if countif_通配符+countif()解决大于15位数的计数问题

    excel的最大精度是15位,如果一个单元格中存储的数字超过15位,那么函数在计算的时候将会出现问题,它们会将15位之后的数字变成0. 在这种情况下,需要在函数中加入通配符,例如,统计A列中,A1出现 ...

最新文章

  1. Apache Commons包 StringUtils工具类深入整理(转载)
  2. 万分之二用百分之怎么表示_2020年元旦放假通知!周三放1天!不挪假连休,你打算怎么安排?...
  3. ArrayList源码分析(基于JDK1.6)
  4. 一个简单粗暴的爬虫 - 必应今日美图
  5. hdu1796容斥原理
  6. 计算机桌面运行慢,电脑越来越慢原因 电脑运行慢解决方法【详解】
  7. mysql 隔离级别 知乎_TiDB 事务隔离级别
  8. xcode5(iOS7)新特性-asset catalog与image slicing
  9. 长江存储年底提供自研32层堆叠3D NAND闪存样品
  10. el-table处理某一行样式;el-table表格row-class-name无效原因;el-table格式化某行样式和数据
  11. AngularJs 时间格式化处理
  12. dede织梦调用顶级二级栏目及下三级栏目方法!
  13. 26.TCP/IP 详解卷1 --- Telnet 和 Rlogin : 远程登录
  14. syslog可能引起得问题_电动车控制器经常出现的问题分析
  15. 城市场景车路协同网络需求研究
  16. 机器学习之有监督学习,无监督学习,半监督学习
  17. POJ 3088 Push Botton Lock 笔记
  18. json生成shp_shp与json互转(转载)
  19. 7个最好的文件存储网站
  20. NBA现役球员季后赛总得分排名前十都有谁?

热门文章

  1. Linux入门:usermod - 修改用户帐户信息
  2. linux中程序包管理方式出现的原由(转载)
  3. 老李分享:HTTP session原理及应用 1
  4. 卸载SD卡对MediaServer的处理
  5. POJ 2010 Moo University - Financial Aid【堆的应用】
  6. protobuf vc2008编译
  7. ASP.NET Google Maps Javascript API V3 实战基础篇一检测用户位置
  8. curl error code 60 51 代码解决方式
  9. L3-023 计算图 (30 分)--PAT 团体程序设计天梯赛 GPLT
  10. 取消c++所设置的cout中setprecision输出的格式