2 1 1 3 1 1 1 2 1000000 1
1 0 0
感想:暑期积分赛又跪了一场,一题都木有A啊,但是看了题解之后,竟然好多都是水过的,当时是自己先看了F,觉得很有把握,然后就开始写,大概二十分钟,WA了一发,仔细研究程序觉得木有问题,还是没有水过去。。。最后吉吉给了几个测试数据,我看了看,不能总是选5步里面第一个跟它一样的,比赛完后,听说可以找5步最后一个和他相同的,不过自己改成这样也没A掉衰死了TAT。。。当时想到了DFS,但是吉吉说深度太深,不好下手。让博博看一下是不是dp,然后分析了下状态可以保存,只是找不到转移方程还是什么。。吉吉的搜索K题WA掉了,博博的线段树A题也TLE,整个情绪也不是很好,只能自己继续磨那个题,到最后真的跪了。
题目大意:给你一个栈,每次只能出栈顶和离栈顶五步以内(含五步)的元素,要求这个元素必须和栈顶相同。
可以把栈出空,输出1,否则输出0.
解题思路:自己写了两种,一种是暴力找,详见AC代码1;
还有一种是DFS,这个相对严密一点,详见AC代码2.
不过正解却是 HDU 4272 LianLianKan 状态压缩DP
只能说是水过,这个题的数据。。不想多说什么了。。。
题目地址:LianLianKan
AC代码1:暴力求解
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int visi[1002],a[1002]; int main() { int n,i,j,flag; while(~scanf("%d",&n)) { for(i=1;i<=n;i++) scanf("%d",&a[i]); if(n&1) { puts("0"); continue; } flag=0; int t=0; memset(visi,0,sizeof(visi)); while(t<n) //到最后没消完的话可以继续消,此种有漏洞。就是可以先出去中间的 { int flag1=0; for(i=n;i>1;i--) { if(visi[i]) continue; int step=1; //此处判断步数的去掉也可以AC。。。 for(j=i-1;j>=0;j--) { if(visi[j]) continue; if(step>5) break; //此处判断步数的去掉也可以AC。。。 step++; // if(a[i]==a[j]) { visi[i]=visi[j]=1; //cout<<i<<" "<<j<<endl; flag1=1; t+=2; break; } } } if(flag1==0) { flag=1; break; } } if(flag) puts("0"); else puts("1"); } return 0; }
12
5 2 4 3 1 5 2 1 3 4 1 1
12
1 3 3 5 5 4 4 1 2 3 3 2
第一组应该输出1,第二组应该输出0.我说下我大概的思路。水过的原因就在这里,因为第二组数据输出也是1.因为我判断的如果栈非空的话就继续进行。例如第一组数据消去的位置是 12与11 9与4 8与5 7与2 6与1 10与3.
而到了第二组数据,这样判断就过不了了。
说测试数据很坑是因为上面如果去掉step判断五步神马的也可以过,这。。情何以堪啊。。。我竟然没水过去
然后参见AC代码2:DFS
#include<cstdio> #include<string> #include<iostream> #include<map> #include<cstring> #include<algorithm> using namespace std; int a[1005],visi[1005]; map<int,int> map1; int dfs(int n) { while(n>0&&visi[n]) n--; if(n==0)return 1; int step=0,j=n-1; while(step<5) { if(j<=0) return 0; //没有找到5步以内可以到达的点 if(visi[j]) { j--; continue; } if(a[n]==a[j]) { visi[j]=1; visi[n]=1; if(dfs(n-1)) return 1; visi[j]=0; visi[n]=0; //回溯的过程 } j--; step++; //找不到的话,step+1,j-1. } return 0; } int main() { int n,flag; while(~scanf("%d",&n)) { map1.clear(); flag=0; memset(visi,0,sizeof(visi)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); map1[a[i]]++; //统计个数,如果某个数出现奇数次的话,直接输出1,否则会TLE } if(n&1) { printf("0\n"); continue; } map<int,int>::iterator x; //第二维存放数量 for(x=map1.begin();x!=map1.end();x++) { if((x->second)&1) { flag=1; break; } } if(flag==1) { printf("0\n"); continue; } printf("%d\n",dfs(n)); //cout<<"1"<<endl; //此处直接输出1也可以AC。。。。 } return 0; }
代码相对来说还是比较严谨的,但是当我听说不需要dfs,先判断&1,再判断个数&1.不符合就直接输出1即可。。然后当时瞬间就石化了。。。。如上面直接输出1.