1. 程式人生 > >記又一次unhappy考試(10.6)

記又一次unhappy考試(10.6)

爆零自動機
unhappy
還好有人陪我爆零。
據說題目很簡單,也據說程式碼很短,最後知道真相的我眼淚掉下來。。。。

題解時間

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;
}

整天氧氣開開我已經沒有希望了