記又一次unhappy考試(10.6)
阿新 • • 發佈:2019-01-01
爆零自動機
還好有人陪我爆零。
據說題目很簡單,也據說程式碼很短,最後知道真相的我眼淚掉下來。。。。
題解時間
T1題解
T1自爆了,還沒寫。
好了把T1膜完了,現在補上去。
T1的思路真是“簡單清新”。圖是一個帶環的樹,而且保證只有一個環。我們只要對於一條鏈上的所有小的子樹依次DP,然後判斷起點和終點的位置,如果起點和終點在一棵樹上,那麼只要子樹上瞎搞就好了;如果不在一棵樹上,就得考慮多棵樹的影響。在統計距離的時候,採用相對距離,如P1和P2相距L1,P1和P3相距L2,可知P2和P3相距L2-L1,於是計算的時候只需要簡單粗暴地給P2到P3的距離暴力減掉L2-L1,這樣前面記錄的距離就都不需要進行改動了,真神奇。
程式碼如下:
/***********************
orz orz orz nbdhhzh ypa
***********************/
#pragma GCC optimize ("O2")
#include <bits/stdc++.h>
#define C(a) memset(a,0,sizeof(a))
#define M 400010
using namespace std;
int n,m,i,j,l,lj,T,cas,cnt,S,ans,tot;
int v[M],a[M],b[M],c[M],fa[M],d[M],mx[M],f[M],p[M],q[M],he[M],to[M],ne[M];
inline void add(int x,int y){to[++tot]=y;ne[tot]=he[x];he[x]=tot;}
inline void up(int x,int y,int k){
if(x>y) swap(x,y);
if(k>ans||k==ans&&x<S||k==ans&&x==S&&y<T) S=x,T=y,ans=k;
}
inline void dfs(int x){
v[x]=1;int i,y;
for(i=he[x];y=to[i],i;i=ne[i]){
if (!f[i]&&!cnt) if(!v[y])
f[i]=f[i^1]=1,fa[y]=i,dfs(y);
else{
for(int j=x;j!=y;j=to[fa[j]^1])
f[fa[j]]=f[fa[j]^1]=2,c[++cnt]=j;
c[++cnt]=y;f[i]=f[i^1]=2;return;
}
}
}
inline void dfs1(int x){
int i,y,mx1=x,mx2=x;
for(d[x]=d[fa[x]]+1,mx[x]=x,i=he[x];y=to[i],i;i=ne[i])
if(!f[i]){
f[i]=f[i^1]=1;fa[y]=x;dfs1(y);
if(d[mx[y]]>d[mx[x]]||d[mx[y]]==d[mx[x]]&&mx[y]<mx[x]) mx[x]=mx[y];
if(d[mx[y]]>d[mx2]||d[mx[y]]==d[mx2]&&mx[y]<mx2){
mx2=mx[y]; if(d[mx2]>d[mx1]||d[mx2]==d[mx1]&&mx2<mx1) swap(mx1,mx2);
}
}up(mx1,mx2,d[mx1]+d[mx2]+cnt-2*d[x]);
}
int main(){
for(scanf("%d",&lj);tot=1,S=T=ans=cnt=0,lj--;){
C(he),C(ne),C(to),C(v),C(d),C(mx),C(fa),C(f),C(q),C(p);
for(C(a),C(b),C(c),scanf("%d",&n),i=1;i<=n;i++)
scanf("%d%d",&a[i],&b[i]),add(a[i],b[i]),add(b[i],a[i]);
for(dfs(1),i=2;i<=tot;i++) if(f[i]!=2) f[i]=0;
for(i=1;i<=n;i++) v[i]=0,fa[i]=0;
for(i=1;i<=cnt;i++) dfs1(c[i]);
for(i=1;i<=cnt;i++) c[i+cnt]=c[i];
for(i=1;i<=cnt*2;i++) p[i]=d[mx[c[i]]]+i;
for(int w=0,t=i=1;i<=cnt*2;q[++w]=i,i++){
if(q[t]==i-cnt) t++;
if(t<=w) up(mx[c[i]],mx[c[q[t]]],p[q[t]]+d[mx[c[i]]]-i+cnt);
while(t<=w&&((p[i]>p[q[w]])||(p[i]==p[q[w]])&&(c[i]<c[q[w]]))) w--;
}printf("Case #%d: %d %d %d\n",++cas,n*2-ans,S,T);
}return 0;
}
T2題解
簡直就是思考題,思想難度++,實現難度–。驚訝地發現,只要選擇了大於等於6個點,必定有符合條件的三個點(顯然法)。所以只要求出所有可以選的情況,然後再暴力列舉最多5個點不可能的情況減掉,然後就過了。。。。過了。。。。
灰常暴力。。。
程式碼如下:
/*******************
orz orz nbdhhzh ypa
*******************/
#pragma GCC optimize ("O2")
#include <bits/stdc++.h>
#define P 1000000007
using namespace std;
int n,m,T,cas,ans,a,b,c,d,e;
int f[60][60];
bool ok(int x,int y,int z){return f[x][y]==f[y][z]&&f[x][y]==f[x][z];}
int main(){
for(scanf("%d",&T),cas=1;cas<=T;cas++){
memset(f,0,sizeof(f));scanf("%d%d",&n,&m);
ans=((1LL<<n)-1-n-n*(n-1)/2)%P;
for(e=1;e<=m;e++) scanf("%d%d",&a,&b),f[a][b]=f[b][a]=1;
for(a=1;a<=n;a++) for(b=a+1;b<=n;b++) for(c=b+1;c<=n;c++){
for(ans-=!ok(a,b,c),d=c+1;d<=n;d++)
for(ans-=!(ok(a,b,c)|ok(a,b,d)|ok(a,c,d)|ok(b,c,d)),e=d+1;e<=n;e++)
ans-=!(ok(a,b,c)|ok(a,b,d)|ok(a,b,e)|ok(a,c,d)|ok(a,c,e)|
ok(a,d,e)|ok(b,c,d)|ok(b,c,e)|ok(b,d,e)|ok(c,d,e));
ans+=(ans<0)?P:0;
}printf("Case #%d: %d\n",cas,ans);
}return 0;
}
T3題解
T3有個灰常神奇的思路。非常顯然的是,如果你把一個增加
的字母或是替換的字母或是交換過來的字母給刪了,建議你去看一下醫生。然後黈黈黈提出了一個根本不理解為什麼的方案,舉個栗子:
agccct
tcca
一串如果要變到二串,只要把一串
’a‘和’t‘之間的東西全刪了,然後交換’a‘和’t‘然後再把’c‘、’c‘給加進去就好了,於是就神奇了。。。。
對於一串的某個字母,只要在二串裡相同位置向前尋找第一個相同的字母,然後使用以上的操作即可。
程式碼如下:
/******************
orz orz nbdhhzh ypa
******************/
#pragma GCC optimize ("O2")
#include <bits/stdc++.h>
using namespace std;
int t1,t2,t3,t4,n,m,i,j,l1,l2,t,tt1,tt2;
int f[4010][4010],g[2][4010][30];
char s1[4010],s2[4010];
int main(){
scanf("%d%d%d%d%s%s",&t1,&t2,&t3,&t4,s1+1,s2+1);
for(l1=strlen(s1+1),l2=strlen(s2+1),i=1;i<=l1;i++){
for(f[i][0]=i*t2,j=0;j<26;j++) g[0][i][j]=g[0][i-1][j];
if(i>1) g[0][i][s1[i-1]-97]=i-1;
}for(i=1;i<=l2;i++){
for(f[0][i]=i*t1,j=0;j<26;j++) g[1][i][j]=g[1][i-1][j];
if(i>1) g[1][i][s2[i-1]-97]=i-1;
}for(i=1;i<=l1;i++) for(j=1;j<=l2;j++){
f[i][j]=min(f[i-1][j]+t2,f[i][j-1]+t1);
t=(s1[i]!=s2[j])*t3+f[i-1][j-1];
if(f[i][j]>t) f[i][j]=t;
if((tt1=g[0][i][s2[j]-97])&&(tt2=g[1][j][s1[i]-97]))
t=f[tt1-1][tt2-1]+(i-tt1-1)*t2+(j-tt2-1)*t1+t4,
f[i][j]=(f[i][j]>t)?t:f[i][j];
}printf("%d\n",f[l1][l2]);return 0;
}
整天氧氣開開我已經沒有希望了