训练报告 18春组队04 2014西安全国邀请赛
Solved | A | HDU 4847 | Wow! Such Doge! |
Solved | B | HDU 4848 | Wow! Such Conquering! |
Solved | C | HDU 4849 | Wow! Such City! |
Solved | D | HDU 4850 | Wow! Such String! |
E | HDU 4851 | Wow! Such Precision! | |
F | HDU 4852 | Wow! Such Tetris! | |
G | HDU 4853 | Trader Dogy | |
H | HDU 4854 | Round-table Conference | |
I | HDU 4855 | Goddess | |
Solved | J | HDU 4856 | Tunnels |
要有求胜意志和竞技心态.....
B样例没看懂,但是自己按照题意分析了下,如果是直接暴力,30!铁定炸,状态压缩dp n^2*2^30也会炸,就放弃了
实际上可以用强力剪枝剪过去,不知道那些出题人是如何精准的算出这种题剪枝后复杂度的...好神奇
C WA了2发才AC,第一次是因为没关调试信息.....而且我数组开小了,他居然返回了WA而不是RE...然后就又WA了一次,最后才发现数组问题,这种水题居然写了这么久...也是跪了
D交给队友想了,期间队友想出了26^4是最大限度,但是我觉得应该都存在,也是脑残,明显26^4中,任何4的串都出现过的...当时如果写D的话,我应该(可)能怼出来个暴力吧
J觉得就是搜索,读题读的比B早,想把图和点抽象出来,成一个只有隧道的的小图,应该可以暴力,但是写出来想不到怎么剪枝,怼了好久才发现是个裸的不反回的TSP问题,状态压缩DP写的太少,没调出来...
其实J一开始就看出来是个NPC问题,NPC问题+15个点,2^15*n^2不会TLE,很明显的状态压缩,我居然活生生写了1小时的暴搜才转正...
菜啊...
当然,这次的最大的问题是,缺少求胜心态,对于难题不想怼...看出来是个状压之后瞬间不想写了,不应该的,无论是练习赛还是什么,都应该全力以赴,写到最后一秒..
1.要有求胜意志和竞技心态.....
2.状态压缩Dp这种东西,就算成铜牌题,也没啥奇怪的,不应该只抱着什么并查集,最短路,生成树,kmp不放,然后意淫自己混个铜滚粗,不存在,说想拿银就得有银的水平,银牌区大佬现场能写出来的,都得去练去做..
3.高级算法不可怕,可怕的是学了之后,比赛打得太少,结果写不出来...或者是之前写过的,结果比赛没看出来/没写出来...比如J的数据量一看,傻子都知道是状压DP,亏我还写过TSP呢..
4.组队打3星题意义不大,只能自我安慰
5.要有求胜意志和竞技心态.....得多打紧脏刺激的个人赛
补题:
B
可以有一个很强的剪枝,
因为求的是累加和
所以前几个点会被重复叠加,所以用公式进行压缩和之前的最优解进行比较,可以在一下子就吧非最优解剪枝掉
除此之外,对截止时间的可行性剪枝也是必须的...
#include <bits/stdc++.h> using namespace std; const int maxn=50; const int maxm=5e6+10; const int len=26*26*26*26; const int INF=0x3f3f3f3f; int casn,n,m,k; int g[maxn][maxn]; int dl[maxn]; int ans; int vis[maxn]; int mxdl; void dfs(int now,int sum,int dis,int num){ if(sum+dis*(n-num)>=ans) return; if(dis>dl[now]) return; for(int i=2;i<=n;i++){ if(!vis[i]&&dis+g[now][i]>dl[i]) return; } if(num==n){ ans=min(ans,sum); return ; } for(int i=1;i<=n;i++){ if(!vis[i]){ vis[i]=1; dfs(i,sum+dis+g[now][i],dis+g[now][i],num+1); vis[i]=0; } } } int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif while(cin>>n){ mxdl=0; memset(g,0x3f,sizeof g); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ cin>>g[i][j]; } } for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ g[i][j]=min(g[i][j],g[i][k]+g[k][j]); } } } for(int i=2;i<=n;i++){ cin>>dl[i]; mxdl=max(dl[i],mxdl); } ans=INF; memset(vis,0,sizeof vis); vis[1]=1; dfs(1,0,0,1); if(ans==INF) puts("-1"); else cout<<ans<<endl; } #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
D
我比赛的时候脑子抽筋了,认为D是可以存在无限长度的..结果整个队伍的时间都在J上了,让J霸占了所有机时,很亏
其实给D一个机会应该(可)能写出来的......
我们要找一个最长的,首先考虑,如果把4和4以下的排列全部输出了,4以上显然是不存在的,因为长度4以上肯定包含一个出现过的子串...
那可以确定是存在无解的,大概就是26^4这么长左右
但是26^4中 是否一定会出现首位相接的排列导致重复子串呢...
不一定,很显然,我们最长的情况是构造一个字符串,遍历了所有长度为4的排列
然后,我们这样想...把每2个长度为4的字符串(aaaa) (baaa) 看成一个点(aaa)和一个边(a) 另一个点(baa)以及他向后面点的边(a)
显然,每个点 可以在它的前面和后面各连一个边(a-z) 换句话说,所有点的度数都是....偶数
//(aaa)这种 显然只能连一个(a)边,因为是回文的..但是度数依然是偶数的
根据欧拉回路的性质
"无向图所有点的度数均为偶数时,必然存在一条欧拉回路"
至于..为啥是欧拉路不是欧拉回路...
一个很精髓的地方到了,如果是欧拉路,那就是遍历所有的排列 26^4,最大长度26^4
但是,但是,如果是欧拉回路,你就能回到起点了!!比如从aaa出发最后到zzz 你的长度肯定是26^4 然后 因为是回路,你可以回到起点,也就是再走一个aaa
最终长度是26^4+3 !!!
#include <bits/stdc++.h> using namespace std; const int maxn=27; const int maxm=5e6+10; const int len=26*26*26*26; const int INF=0x3f3f3f3f; int casn,n,m,k; char p[256][256][256]; int s[5]; int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif while(~scanf("%d",&n)){ if(n>len+3) { puts("Impossible"); continue; } s[0]=s[1]=s[2]=25; for(int i=0;i<=25;i++){ for(int j=0;j<=25;j++){ for(int k=0;k<=25;k++){ p[i][j][k]=0; } } } for(int i=0;i<min(n,3);i++){ putchar((char)(s[i]+'a')); } for(int i=3;i<n;i++){ s[(i-1)%3]=p[s[(i-3)%3]][s[(i-2)%3]][s[(i-1)%3]]++; putchar((char)(s[(i-1)%3]+'a')); } puts(""); } #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }
J
裸的TSP问题,只不过不用回到起点,初始化改一改就行,期间用bfs求距离 复杂度(n^2*n^2*2^15)
#include <bits/stdc++.h> using namespace std; const int maxn=50; const int maxm=100; const int INF=0x3f3f3f3f; int casn,n,m,k; char mp[123][123]; int sx[maxn],sy[maxn],tx[maxn],ty[maxn]; struct node{ int x,y,c; }; bool vis[maxn][maxn]; int dis[maxn]; int dd[maxn][maxn]; int dp[maxn][1<<16]; const int dir[4][2]={1,0,-1,0,0,1,0,-1}; #define dx dir[d][0] #define dy dir[d][1] queue<node>q; int bfs(int st,int ed){ while(!q.empty())q.pop(); memset(dis,0x3f,sizeof dis); memset(vis,0,sizeof vis); q.push((node){tx[st],ty[st],0}); while(!q.empty()){ node now=q.front();q.pop(); if(now.x==sx[ed]&&now.y==sy[ed]){ return now.c; } for(int d=0;d<4;d++){ int x=now.x+dx; int y=now.y+dy; if(x&&y&&x<=n&&y<=n&&mp[x][y]!='#'&&!vis[x][y]){ vis[x][y]=1; q.push((node){x,y,now.c+1}); } } } return -1; } int main(){ //#define test #ifdef test freopen("in.txt","r",stdin);freopen("out.txt","w",stdout); #endif while(cin>>n>>m){ memset(mp,'#',sizeof mp); for(int i=1;i<=n;i++){ scanf("%s",(mp[i]+1)); } for(int i=0;i<m;i++){ cin>>sx[i]>>sy[i]>>tx[i]>>ty[i]; } memset(dp,-1,sizeof dp); memset(dd,0x3f,sizeof dd); for(int i=0;i<m;i++)dp[i][1<<i]=0; for(int state=0;state<(1<<m);state++){ for(int i=0;i<m;i++){ if(state&(1<<i)&&dp[i][state]!=-1){ for(int j=0;j<m;j++){ if(!((1<<j)&state)&&dd[j][i]!=-1){ if(dd[j][i]==INF) dd[j][i]=bfs(j,i); if(dd[j][i]==-1){ continue; } int k=state|(1<<j),cost=dp[i][state]+dd[j][i]; if(dp[j][k]==-1||dp[j][k]>cost){ dp[j][k]=cost; } } } } } } int ans=-1; for(int i=0;i<m;i++){ if(dp[i][(1<<m)-1]==-1)continue; if(ans==-1||ans>dp[i][(1<<m)-1]) ans=dp[i][(1<<m)-1]; } cout<<ans<<endl; } #ifdef test fclose(stdin);fclose(stdout);system("out.txt"); #endif return 0; }