这个题的搜索可以打到48分……

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=;
bool must[N],in[N];
int cnt;
int n,a[N][N],q[N],b[N];
inline bool judge(int len,int lim){
return lim-len>=cnt;
}
inline bool check(int len){
register int i,j,k,pos,g;
register bool can;
for(i=;i<=n;++i){
can=false;
for(j=;j<=len;++j){
if(len-j+>=a[i][]){
pos=,g=;
for(k=j;k<=len;++k){
if(in[q[k]])continue;
if(q[k]!=a[i][pos+]){g=-;break;}
b[++pos]=q[k];
in[q[k]]=true;
}
can=g!=-&&pos==a[i][];
while(pos--)in[b[pos+]]=false;
if(can)break;
}
if(j>=a[i][]){
pos=,g=;
for(k=j;k>;--k){
if(in[q[k]])continue;
if(q[k]!=a[i][pos+]){g=-;break;}
b[++pos]=q[k];
in[q[k]]=true;
}
can=g!=-&&pos==a[i][];
while(pos--)in[b[pos+]]=false;
if(can)break;
}
}
if(!can)return false;
}
return true;
}
inline bool dfs(int pos,int lim){
if(!judge(pos-,lim))return false;
if(pos==lim+)return check(pos-);
register int i;
register bool keep;
for(i=;i<=;++i)
if(i!=q[pos-]){
q[pos]=i;
if(must[i]){
must[i]=false,--cnt;
keep=true;
}else keep=false;
if(dfs(pos+,lim))return true;
if(keep)must[i]=true,++cnt;
}
return false;
}
int main(){
//freopen("rio.in","r",stdin);
scanf("%d",&n);
register int i,j;
for(i=;i<=n;++i){
while(true){
scanf("%d",&j);
if(!j)break;
a[i][++a[i][]]=j;
must[j]=true;
}
}
for(i=;i<=;++i)
cnt+=must[i];
for(i=cnt;i<=;++i){
if(cnt<&&i==)break;
if(dfs(,i)){
printf("%d\n",i);
return ;
}
}
puts("-1");
return ;
}

Kod

搜索的时候减枝实在是太重要了,其次梦想与搜索之间的平衡也是很重要的,但是一定要合理且适当.
正解很神.
贴一发题解:

还有一位大佬的代码注释也很好:https://loj.ac/submission/66283
我就是看的这两个资料,然后码出来的.(把写法从spfa改成记忆化dfs会快3倍……)
在这里说一下坑吧,就是正着走的状态可以在半截出现,倒着走的状态可以在半截消失.
分享一下代码.
正着走的单向40分:

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=;
const int F=;
const int Inf=0x3f3f3f3f;
int n,ans,full,bit[N],a[N][N],l[N],b[N];
int f[N][N][F];
bool ex[N][N],can[N][N][N],in[N],fin[N][N][F];
inline bool check(int id,int len,int to){
register int i,pos=;
memset(in,,sizeof(in));
for(i=;i<=len;++i)
in[a[id][i]]=true;
for(i=;i<=l[to];++i){
if(in[a[to][i]])continue;
b[++pos]=a[to][i];
in[a[to][i]]=true;
}
if(pos!=l[id]-len)return false;
for(i=len+;i<=l[id];++i)
if(a[id][i]!=b[i-len])
return false;
return true;
}
inline void dfs(int id,int pos,int st){
//printf("%d %d %d\n",id,pos,st);
if(fin[id][pos][st]){
//puts("GG");
ans=std::min(ans,f[id][pos][st]);
return;
}
register int i;
for(i=;i<=n;++i)
if(i!=id&&(bit[i]&st)==)
if(can[id][pos][i]&&f[i][][st|bit[id]]>f[id][pos][st]){
f[i][][st|bit[id]]=f[id][pos][st];
dfs(i,,st|bit[id]);
}
if(pos!=l[id]&&f[id][pos+][st]>f[id][pos][st]+){
f[id][pos+][st]=f[id][pos][st]+;
dfs(id,pos+,st);
}
}
int main(){
//freopen("rio.in","r",stdin);
scanf("%d",&n);
full=(<<n)-;
register int i,j,k;
for(i=;i<=n;++i){
bit[i]=<<(i-);
while(true){
scanf("%d",&j);
if(!j)break;
a[i][++l[i]]=j;
ex[i][j]=true;
}
}
for(i=;i<=n;++i)
for(j=;j<=l[i];++j)
for(k=;k<=n;++k)
can[i][j][k]=check(i,j,k);
memset(f,0x3f,sizeof(f));
ans=Inf;
for(i=;i<=n;++i)
fin[i][l[i]][full^bit[i]]=true;
for(i=;i<=n;++i){
f[i][][]=;
dfs(i,,);
}
printf("%d\n",ans==Inf?-:ans);
return ;
}

Kod

倒着走的单向40分:

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=;
const int F=;
const int Inf=0x3f3f3f3f;
int n,ans,full,bit[N],a[N][N],l[N],b[N];
int f[N][N][F];
bool can[N][N][N],in[N],fin[N][N][F];
inline bool check(int id,int len,int to){
register int i,pos=;
memset(in,,sizeof(in));
for(i=;i<=len;++i)
in[a[id][i]]=true;
for(i=;i<=l[to];++i){
if(in[a[to][i]])continue;
b[++pos]=a[to][i];
in[a[to][i]]=true;
}
if(pos!=l[id]-len)return false;
for(i=len+;i<=l[id];++i)
if(a[id][i]!=b[i-len])
return false;
return true;
}
inline void dfs(int id,int pos,int st){
//printf("%d %d %d\n",id,pos,st);
if(fin[id][pos][st]){
//puts("GG");
ans=std::min(ans,f[id][pos][st]);
return;
}
if(!pos){
register int i,j;
for(i=;i<=n;++i)
if(i!=id&&(bit[i]&st)==)
for(j=;j<=l[i];++j)
if(can[i][j][id]&&f[i][j][st|bit[id]]>f[id][pos][st]){
f[i][j][st|bit[id]]=f[id][pos][st];
dfs(i,j,st|bit[id]);
}
}
if(pos&&f[id][pos-][st]>f[id][pos][st]+){
f[id][pos-][st]=f[id][pos][st]+;
dfs(id,pos-,st);
}
}
int main(){
//freopen("rio.in","r",stdin);
scanf("%d",&n);
full=(<<n)-;
register int i,j,k;
for(i=;i<=n;++i){
bit[i]=<<(i-);
while(true){
scanf("%d",&j);
if(!j)break;
a[i][++l[i]]=j;
}
}
for(i=;i<=n;++i)
for(j=;j<=l[i];++j)
for(k=;k<=n;++k)
can[i][j][k]=check(i,j,k);
memset(f,0x3f,sizeof(f));
ans=Inf;
for(i=;i<=n;++i)
fin[i][][full^bit[i]]=true;
for(i=;i<=n;++i){
f[i][l[i]][]=;
dfs(i,l[i],);
}
printf("%d\n",ans==Inf?-:ans);
return ;
}

Kod

经过我不断修改的清真美丽100分代码:

#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
std::set<LL> ext;
const int N=;
const int F=;
const int Inf=0x3f3f3f3f;
int n,full,bit[N],a[N][N],l[N];
int f[N][N][N][N][F];
bool ex[N][N][N],can[N][N][N],in[N],vis[N][N][N][N][F];
inline bool check(int id,int len,int to){
int i,pos=;
memcpy(in,ex[id][len],sizeof(in));
for(i=;i<=l[to];++i){
if(in[a[to][i]])continue;
++pos,in[a[to][i]]=true;
if(a[to][i]!=a[id][len+pos])
return false;
}
if(pos!=l[id]-len)return false;
return true;
}
inline void Init(){
scanf("%d",&n);
int i,j,k;
LL key;
for(i=;i<=n;++i){
l[i]=,key=;
memset(ex[i],,sizeof(ex[i]));
bit[i]=<<(i-),j=;
while(j){
scanf("%d",&j);
key=key*+j;
a[i][++l[i]]=j;
for(k=;k<=l[i];++k)
if(a[i][k])
ex[i][l[i]][a[i][k]]=true;
}
--l[i];
if(ext.count(key))--i,--n;
ext.insert(key);
}
full=(<<n)-;
for(i=;i<=n;++i){
can[][][i]=true;
for(j=;j<=l[i];++j)
for(k=;k<=n;++k)
can[i][j][k]=check(i,j,k);
}
memset(f,0x3f,sizeof(f));
}
#define cover(id1,pos1,id2,pos2,st,add) (k=std::min(dfs(id1,pos1,id2,pos2,st)+add,k))
inline int dfs(int id1,int pos1,int id2,int pos2,int st){
if(st==full&&pos1==l[id1]&&!pos2)return ;
int i,j,&k=f[id1][pos1][id2][pos2][st];
if(vis[id1][pos1][id2][pos2][st])return k;
vis[id1][pos1][id2][pos2][st]=true;
if(id2&&!pos2){
for(i=;i<=n;++i)
if(i!=id1&&!(bit[i]&st))
for(j=;j<=l[i];++j)
if(can[i][j][id2])
cover(id1,pos1,i,j,st|bit[i],);
}
for(i=;i<=n;++i)
if(can[id1][pos1][i]&&!(bit[i]&st))
cover(i,,id2,pos2,st|bit[i],);
if(pos1==l[id1]&&!pos2)return k;
if(pos1!=l[id1]&&(ex[id2][pos2+][a[id1][pos1+]]||!id2))
cover(id1,pos1+,id2,pos2,st,);
if(pos2&&(ex[id1][pos1][a[id2][pos2]]||!id1))
cover(id1,pos1,id2,pos2-,st,);
if(pos1!=l[id1]&&pos2&&a[id2][pos2]==a[id1][pos1+])
cover(id1,pos1+,id2,pos2-,st,);
return k;
}
inline void Work(){
int i,ans=Inf;
for(i=;i<=n;++i)
ans=std::min(dfs(,,i,l[i],bit[i]),ans);
printf("%d\n",ans==Inf?-:ans);
}
int main(){
Init(),Work();
return ;
}

Kod

我第一次A掉的时候写的100分(这个代码又臭又长又屎):

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=;
const int F=;
const int Inf=0x3f3f3f3f;
int n,ans,full,bit[N],a[N][N],l[N],b[N];
int f[N][N][N][N][F];
bool ex[N][N][N],can[N][N][N],in[N],fin[N][N][N][N][F];
inline bool check(int id,int len,int to){
register int i,pos=;
memset(in,,sizeof(in));
for(i=;i<=len;++i)
in[a[id][i]]=true;
for(i=;i<=l[to];++i){
if(in[a[to][i]])continue;
b[++pos]=a[to][i];
in[a[to][i]]=true;
}
if(pos!=l[id]-len)return false;
for(i=len+;i<=l[id];++i)
if(a[id][i]!=b[i-len])
return false;
return true;
}
inline void dfs(int id1,int pos1,int id2,int pos2,int st){
//printf("%d %d %d %d %d\n",id1,pos1,id2,pos2,st);
if(fin[id1][pos1][id2][pos2][st]){
//puts("GG");
ans=std::min(ans,f[id1][pos1][id2][pos2][st]);
return;
}
if(id2&&!pos2){
register int i,j;
for(i=;i<=n;++i)
if(i!=id1&&i!=id2&&(bit[i]&st)==)
for(j=;j<=l[i];++j)
if(can[i][j][id2]&&f[id1][pos1][i][j][st|bit[id2]]>f[id1][pos1][id2][pos2][st]){
f[id1][pos1][i][j][st|bit[id2]]=f[id1][pos1][id2][pos2][st];
dfs(id1,pos1,i,j,st|bit[id2]);
}
if(id1){
if(f[id1][pos1][][][st|bit[id2]]>f[id1][pos1][id2][pos2][st]){
f[id1][pos1][][][st|bit[id2]]=f[id1][pos1][id2][pos2][st];
dfs(id1,pos1,,,st|bit[id2]);
}
}else{
for(i=;i<=n;++i)
if(i!=id2&&(bit[i]&st)==&&f[i][][][][st|bit[id2]]>f[id1][pos1][id2][pos2][st]){
f[i][][][][st|bit[id2]]=f[id1][pos1][id2][pos2][st];
dfs(i,,,,st|bit[id2]);
}
}
}
if(id1){
register int i;
for(i=;i<=n;++i)
if(i!=id1&&i!=id2&&(bit[i]&st)==)
if(can[id1][pos1][i]&&f[i][][id2][pos2][st|bit[id1]]>f[id1][pos1][id2][pos2][st]){
f[i][][id2][pos2][st|bit[id1]]=f[id1][pos1][id2][pos2][st];
dfs(i,,id2,pos2,st|bit[id1]);
}
}else{
register int i;
for(i=;i<=n;++i)
if(i!=id2&&(bit[i]&st)==&&f[i][][id2][pos2][st]>f[id1][pos1][id2][pos2][st]){
f[i][][id2][pos2][st]=f[id1][pos1][id2][pos2][st];
dfs(i,,id2,pos2,st);
}
}
if((id2==||pos2==)&&(id1==||pos1==l[id1]))return;
if(id1&&pos1!=l[id1]&&(ex[id2][pos2+][a[id1][pos1+]]||!id2)&&f[id1][pos1+][id2][pos2][st]>f[id1][pos1][id2][pos2][st]+){
f[id1][pos1+][id2][pos2][st]=f[id1][pos1][id2][pos2][st]+;
dfs(id1,pos1+,id2,pos2,st);
}
if(id2&&pos2&&(ex[id1][pos1+][a[id2][pos2]]||!id1)&&f[id1][pos1][id2][pos2-][st]>f[id1][pos1][id2][pos2][st]+){
f[id1][pos1][id2][pos2-][st]=f[id1][pos1][id2][pos2][st]+;
dfs(id1,pos1,id2,pos2-,st);
}
//printf("<>%d %d %d %d %d\n",id1,pos1,id2,pos2,st);
if(id1&&id2&&pos2&&pos1!=l[id1]&&a[id2][pos2]==a[id1][pos1+]&&f[id1][pos1+][id2][pos2-][st]>f[id1][pos1][id2][pos2][st]+){
//puts("OK");
f[id1][pos1+][id2][pos2-][st]=f[id1][pos1][id2][pos2][st]+;
dfs(id1,pos1+,id2,pos2-,st);
}
//else puts("NO");
}
int main(){
//freopen("rio.in","r",stdin);
//freopen("wq.out","w",stdout);
scanf("%d",&n),full=(<<n)-;
register int i,j,k;
for(i=;i<=n;++i){
bit[i]=<<(i-);
while(true){
scanf("%d",&j);
if(!j)break;
a[i][++l[i]]=j;
}
}
for(i=;i<=n;++i)
for(j=;j<=l[i];++j)
for(k=;k<=n;++k)
can[i][j][k]=check(i,j,k);
for(i=;i<=n;++i)
for(j=;j<=;++j)
for(k=;k<=j;++k)
ex[i][j][a[i][k]]=true;
memset(f,0x3f,sizeof(f));
ans=Inf;
for(i=;i<=n;++i){
for(j=;j<=n;++j){
if(i==j)continue;
fin[i][l[i]][j][][full^bit[i]^bit[j]]=true;
f[i][][j][l[j]][]=;
}
fin[i][l[i]][][][full^bit[i]]=true;
f[i][][][][]=;
fin[][][i][][full^bit[i]]=true;
f[][][i][l[i]][]=;
}
for(i=;i<=n;++i){
for(j=;j<=n;++j){
if(i==j)continue;
dfs(i,,j,l[j],);
}
dfs(i,,,,);
dfs(,,i,l[i],);
}
printf("%d\n",ans==Inf?-:ans);
return ;
}

Kod

我在这里说一下我对于这道题的解法的理解吧.
看到题解之后,就会发现这道题dp的状态定义很谜.我们先看正着走单向的,我们之所以这么定义,是因为最终方案也一定是这样构成的,这很好理解.再看倒着走的,同样,我们之所以这么定义,也是因为最终方案也一定是这样构成的.那么我们再看双向的状态,思考一下,发现也是这样的.那么我们这么转移就一定没有问题.而这神奇的状态设计从哪里来呢.我觉得,就是抓出题目给出的操作的性质——“远观不如近看”,让“近看”去满足“远观”,用“远观”去匹配“近看”,再加上增量构造的思路,就迸发出了这道题的状态以及转移.
现在以我的水平,我对于这道题的理解大概也就这么多,也许以后会有更好的理解把.利用状态压缩,以及对于特殊的问题,设计合理的状态,大概就是我从这道题里学到的宝贵的东西,对于设计状态,我还是摸不着头脑的.

LOJ #6037.「雅礼集训 2017 Day4」猜数列 状压dp的更多相关文章

  1. loj 6037 「雅礼集训 2017 Day4」猜数列 - 动态规划

    题目传送门 传送门 题目大意 有一个位置数列,给定$n$条线索,每条线索从某一个位置开始,一直向左或者向右走,每遇到一个还没有在线索中出现的数就将它加入线索,问最小的可能的数列长度. 依次从左到右考虑 ...

  2. Loj 6036 「雅礼集训 2017 Day4」编码 - 2-sat

    题目传送门 唯一的传送门 题目大意 给定$n$个串,每个串只包含 ' .问是否可能任意两个不同的串不满足一个是另一个的前缀. 2-sat的是显然的. 枚举每个通配符填0还是1,然后插入Trie树. 对 ...

  3. 2018.10.27 loj#6035. 「雅礼集训 2017 Day4」洗衣服(贪心+堆)

    传送门 显然的贪心题啊...考试没调出来10pts滚了妙的一啊 直接分别用堆贪心出洗完第iii件衣服需要的最少时间和晾完第iii件衣服需要的最少时间. 我们设第一个算出来的数组是aaa,第二个是bbb ...

  4. LOJ#6035. 「雅礼集训 2017 Day4」洗衣服

    传送门 先处理出每一件衣服最早什么时候洗完,堆+贪心即可 然后同样处理出每件衣服最早什么时候烘干 然后倒序相加取最大值 # include <bits/stdc++.h> using na ...

  5. LOJ #6035.「雅礼集训 2017 Day4」洗衣服 贪心

    这道题的贪心好迷啊~我们对于两个过程进行单独贪心,然后再翻转一个,把这两个拼起来.先说一下单独贪心,单独贪心的话就是用一个堆,每次取出最小的,并且把这个最小的加上他单次的,再放进去.这样,我们得到的结 ...

  6. LOJ #6036.「雅礼集训 2017 Day4」编码 Trie树上2-sat

    记得之前做过几道2-sat裸体,以及几道2-sat前缀优化建图,这道题使用了前缀树上前缀树优化建图.我们暴力建图肯定是n^2级别的,那么我们要是想让边数少点,就得使用一些骚操作.我们观察我们的限制条件 ...

  7. loj #6032. 「雅礼集训 2017 Day2」水箱 线段树优化DP转移

    $ \color{#0066ff}{ 题目描述 }$ 给出一个长度为 \(n\) 宽度为 \(1\) ,高度无限的水箱,有 \(n-1\) 个挡板将其分为 \(n\) 个 \(1 - 1\) 的小格, ...

  8. [LOJ 6031]「雅礼集训 2017 Day1」字符串

    [LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...

  9. [LOJ 6030]「雅礼集训 2017 Day1」矩阵

    [LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...

随机推荐

  1. 内容安全策略(CSP)

    内容安全策略(CSP),其核心思想十分简单:网站通过发送一个 CSP 头部,来告诉浏览器什么是被授权执行的与什么是需要被禁止的.其被誉为专门为解决XSS攻击而生的神器. 1.CSP是什么 CSP指的是 ...

  2. const与readonly常量

    const与readonly常量 const与readonly都是用来定义常量,但是它们有什么区别呢? 下面我们来简要的说明一下: const修饰的常量是编译时常量,如:public const St ...

  3. DoItYourself!

    在杨老师的勉励下,我准备开始“自己”写程序.速度很慢,不过在写的过程中对于用到的几个函数更加熟悉.也尝试多学一点,学透一点.遇到不会的函数,语法不清楚的,还是会百度,不过会自己再敲一遍.重复下去. 下 ...

  4. Thunder团队——选题展示

    团队名称:Thunder 组长:王航 成员:李传康.代秋彤.邹双黛.苗威.宋雨.胡佑蓉.杨梓瑞 项目名称:爱阅app 视频展示: http://www.cnblogs.com/lick468/p/76 ...

  5. 遇到Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so问题的解决方法

    运行一个基于tensorflow的模型时,遇到Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so问题. 解决方法:打开 ...

  6. 读我是一只IT小小鸟有感

    进入大学半年了,每个人都说软件工程是一个非常有前途的高薪职业,但我这半年来都很迷茫,看不清自己的未来,不知道如何度过接下来的三年半时光,虽然我也认为软件工程是有前途的专业,但是经过一学期的学习,发现不 ...

  7. 今目标登录时报网络错误E110

    今目标登录的时候报错了,错误代码:E110不论怎么修改都修复不了,百度相关资料也没有,只能联系客服. 经过好久终于联系上了客服,客服给出的解决方案是修改:Enternet选项: 第一步:打开,控制面板 ...

  8. C#控件之Repeater控件使用

    歡迎大家來討論,修改,一定虛心接受. 1.為什麼使用Repeater控件? 關於把從數據庫讀取的數據綁定到前台頁面,我們可以使用DataGrid.DataGridView以及Repeater來佈局,三 ...

  9. 【leetcode】215. Kth Largest Element in an Array

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

  10. HDU 2156 分数矩阵

    http://acm.hdu.edu.cn/showproblem.php?pid=2156 Problem Description 我们定义如下矩阵:1/1 1/2 1/31/2 1/1 1/21/ ...