日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JZOJ 5711. 【北大夏令营2018模拟5.13】时间幻象

發布時間:2025/3/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JZOJ 5711. 【北大夏令营2018模拟5.13】时间幻象 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Description

Input

從文件 return.in 中讀入數據。
輸入文件的第1行2個整數n,m,表示時間線的長度和轉移的個數。
后面m行每行2個空格隔開的字符串A? ,B? ,描述一組轉移。

Output

輸出到文件 return.out 中。
輸出文件僅1行,1個非負整數,表示答案。

Sample Input

2 3
A B
A C
D D

Sample Output

5
解釋:一種最優方案:AA → AB → BA → BC → CB。

Data Constraint

Solution

  • 我們發現其實所謂字符串轉換只跟每個字母的個數有關,因為相鄰兩個字母可以交換。

  • 首先我們要意識到一點:狀態數和方案數都不會很多!!!

  • 狀態數只有:C4?130+4?1=C333=5456C30+4?14?1=C333=5456 (用擋板問題解決)。

  • 而答案也不會很多,C1530C3015 也沒多大(字母數總和最多才30),并不會爆 long long 。

  • 對于一個狀態(設其A-D的個數分別是p1,p2,p3,n?p1?p2?p3p1,p2,p3,n?p1?p2?p3),

  • 那么它可以轉換成的不同排列個數就是:

    Cp1n?Cp2n?p1?Cp3n?p1?p2?Cn?p1?p2?p3n?p1?p2?p3Cnp1?Cn?p1p2?Cn?p1?p2p3?Cn?p1?p2?p3n?p1?p2?p3

  • 我們將這個值設為這個狀態的權值。

  • 接著我們枚舉那 mm 中轉移方式,將每種狀態轉移出去并連邊(反正狀態數又不多)。

  • 做一遍 tarjan 縮環,一個強連通分量的權值就是其中所有點權之和。

  • 這就變成一個點帶權的DAG了,我們需要求一條最長路徑,

  • 那么直接像拓撲排序一樣DP一遍就好了。

  • 時間復雜度約為 O(C333?m)O(C333?m)

Code

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int N=32,M=6000; struct data {int x,y; }edge[M*N]; int n,m,tot,top,num,cnt; LL ans; int first[M],nex[M*N],en[M*N]; int a[N<<1][5],b[N<<1][5],c[5],d[5]; int name[N][N][N],q[M],deg[M]; int dfn[M],low[M],st[M],col[M]; bool bz[M]; LL val[M],val1[M],g[N][N],f[M]; char s[N],t[N]; inline int min(int x,int y) {return x<y?x:y; } inline int get(int *pos) {return name[pos[1]][pos[2]][pos[3]]; } inline LL calc(int *pos) {return g[n][pos[1]]*g[n-pos[1]][pos[2]]*g[n-pos[1]-pos[2]][pos[3]]; } inline void insert(int x,int y) {nex[++tot]=first[x];first[x]=tot;en[tot]=y; } void ergodic(int x,int y) {if(!y){name[c[1]][c[2]][c[3]]=++tot;return;}if(x>4) return;for(int i=0;i<=y;i++){c[x]=i;ergodic(x+1,y-i);c[x]=0;} } void dfs(int x,int y) {if(!y){int now=get(c);val[now]=calc(c);for(int i=1;i<=m;i++){for(int j=1;j<=4;j++) d[j]=c[j]-a[i][j];bool pd=true;for(int j=1;j<=4;j++)if(d[j]<0){pd=false;break;}if(!pd) continue;for(int j=1;j<=4;j++) d[j]+=b[i][j];int to=get(d);if(now==to) continue;edge[++cnt]=(data){now,to};insert(now,to);}return;}if(x>4) return;for(int i=0;i<=y;i++){c[x]=i;dfs(x+1,y-i);c[x]=0;} } void tarjan(int x) {dfn[x]=low[x]=++tot;bz[st[++top]=x]=true;for(int i=first[x];i;i=nex[i])if(!dfn[en[i]]){tarjan(en[i]);low[x]=min(low[x],low[en[i]]);}elseif(bz[en[i]]) low[x]=min(low[x],dfn[en[i]]);if(dfn[x]==low[x]){num++;do{col[st[top]]=num;bz[st[top--]]=false;}while(st[top+1]^x);} } void work() {int l=0,r=0;for(int i=1;i<=num;i++)if(!deg[i]){q[++r]=i;f[i]=val1[i];if(f[i]>ans) ans=f[i];}while(l<r){int x=q[++l];for(int i=first[x];i;i=nex[i])if(f[x]+val1[en[i]]>f[en[i]]){f[en[i]]=f[x]+val1[en[i]];if(f[en[i]]>ans) ans=f[en[i]];q[++r]=en[i];}} } int main() {freopen("return.in","r",stdin);freopen("return.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%s %s",s+1,t+1);int len=strlen(s+1);for(int j=1;j<=len;j++){a[i][s[j]-'A'+1]++;b[i][t[j]-'A'+1]++;}}for(int i=0;i<=n;i++) g[i][0]=1;for(int i=1;i<=n;i++)for(int j=1;j<=i;j++) g[i][j]=g[i-1][j]+g[i-1][j-1];ergodic(1,n);int node=tot;tot=0;dfs(1,n);tot=0;for(int i=1;i<=node;i++)if(!dfn[i]) tarjan(i);for(int i=1;i<=node;i++) val1[col[i]]+=val[i];memset(first,tot=0,sizeof(first));for(int i=1;i<=cnt;i++)if(col[edge[i].x]^col[edge[i].y]){insert(col[edge[i].x],col[edge[i].y]);deg[col[edge[i].y]]++;}work();printf("%lld",ans);return 0; }

總結

以上是生活随笔為你收集整理的JZOJ 5711. 【北大夏令营2018模拟5.13】时间幻象的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。