【牛客 - 369A】小D的剧场(线性dp)
題干:
鏈接:https://ac.nowcoder.com/acm/contest/369/A
來源:牛客網
?
題目描述
"我明白。"
作為這命運劇場永遠的觀眾,小D一直注視著這片星光璀璨的舞臺,舞臺上,少女們的身姿演繹出了一幕幕動人的場景,令人回味無窮。
有的時候,小D也會自己寫一些歌曲,來加入Starlight的劇本,使得劇本充滿了新的生命力。
現在小D又要準備寫樂譜了,小D寫譜的方式比較獨特。他會先寫出一個按照音符出現順序排成的序列,再進一步整合,每次整合會選取相鄰的三個作為三和弦。整合次數無限。
小D選取的音符形如D5 F6這種形式,例如D5表示D大調sol(這里不考慮升降音)為了方便生成樂譜,他將這些音符進一步轉化了,小D給C D E F G A B重新編號成了1 2 3 4 5 6 7,之后新的音符編號生成方式應為(字母對應的標號-1)*7+數字,例如C7=(1?1)×7+7=7C7=(1?1)×7+7=7
但小D討厭一些他所認為的不優美的和弦,因此他并不希望自己的譜子里面有可能出現這樣的三和弦,也就說音符組成的序列里不應該存在他所討厭的子段,假如C5 F1 A2這三個音符湊成的和弦小D不喜歡,那么序列里面就不能出現C5 F1 A2,C5 A2 F1,A2 C5 F1,A2 F1 C5,F1 A2 C5,F1 C5 A2這六種子段。
現在小D正在推算有多少合法的序列,答案對?109+7109+7?取模。
星屑飄灑的舞臺上,可人綻放的愛之花,請努力讓大家星光閃耀吧!
輸入描述:
第一行為兩個整數 n, q ,表示序列的長度和有多少和弦小D不喜歡. 接下來 q 行,每行三個整數 a, b, c ,表示小D不想出現的和弦輸出描述:
一行一個整數,表示答案示例1
輸入
復制
10 10 18 3 3 43 28 22 42 28 3 48 48 4 29 9 31 47 9 22 1 22 49 15 48 29 2 8 27 4 24 34輸出
復制
382785822示例2
輸入
復制
3 1 1 2 3輸出
復制
117643說明
?一共有6種不合法的序列:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
答案為493?6=117643493?6=117643
備注:
3≤n≤500,0≤q≤117649,1≤a,b,c≤49解題報告:
? ? 眼殘黨表示剛開始沒有讀題、、認為q<=117649 ,正好是49^3嘛,肯定不會有重復,然后就GG了、、2333.。。。
dp[i][j][k]表示前i個字符,其中倒數第二個為j,倒數第一個為k時,可以組成的方案數。
對于狀態的轉移,我們有兩種解法:對于dp[i]的轉移,我們先把源自dp[i-1]的都累加過來,然后看看需要減去多少,這時候枚舉去重完的這tot組和弦,對于每一組,分成:三個數都相同;其中兩個數相同,三個數都不相同,三種情況,分別進行轉移就行了。你如果都直接減6組的話,,那就有可能減多了,樣例1就過不了(別問我怎么知道的,吃完飯回來才想出來)。
第二種解法:也是十分簡單的,先用三維數組標記三位數是否出現過,直接枚舉后三個數[j][k][l],如果沒出現過,那就轉移;如果出現過就continue。
AC代碼1:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e5 + 5; ll dp[505][55][55],dpp[MAX]; int a[MAX],b[MAX],c[MAX],qq[3]; const ll mod = 1e9 + 7; int tot; set<pair<int,pair<int,int> > > ss; int main() {int n,q;cin>>n>>q;for(int x,y,z,i = 1; i<=q; i++) {scanf("%d%d%d",qq,qq+1,qq+2);sort(qq,qq+3);x=qq[0],y=qq[1],z=qq[2];if(ss.count(pm(x,pm(y,z)))) continue;else a[++tot] = x,b[tot]=y,c[tot]=z,ss.insert(pm(x,pm(y,z)));}for(int i = 1; i<=2; i++) {for(int j = 1; j<=49; j++) {for(int k = 1; k<=49; k++) {dp[i][j][k] = 1;}}}for(int i = 3; i<=n; i++) {for(int j = 1; j<=49; j++) {for(int k = 1; k<=49; k++) {for(int l = 1; l<=49; l++) {dp[i][j][k] += dp[i-1][l][j];dp[i][j][k] %= mod;}}} // memset(dpp,0,sizeof dpp); // //求出以i中間的,dpp[i] // for(int j = 1; j<=49; j++) { // for(int k = 1; k<=49; k++) { // dpp[j] += dp[i-1][k][j]; // } // }for(int e = 1; e<=tot; e++) {int A = a[e],B = b[e],C = c[e];int xx[3];xx[0]=A,xx[1]=B,xx[2]=C;sort(xx,xx+3);A=xx[0],B=xx[1],C=xx[2];if(A==B&&B==C) dp[i][A][B] = (dp[i][A][B]+mod - dp[i-1][C][A])%mod;else if(A==B && B!=C) {dp[i][A][B] = (dp[i][A][B]+mod - dp[i-1][C][A])%mod;dp[i][A][C] = (dp[i][A][C]+mod - dp[i-1][B][A])%mod;dp[i][C][A] = (dp[i][C][A]+mod - dp[i-1][B][C])%mod;}else if(A!=B && B==C) {dp[i][A][B] = (dp[i][A][B]+mod - dp[i-1][C][A])%mod;dp[i][B][A] = (dp[i][B][A]+mod - dp[i-1][C][B])%mod;dp[i][B][C] = (dp[i][B][C]+mod - dp[i-1][A][B])%mod;}else {dp[i][A][B] = (dp[i][A][B]+mod - dp[i-1][C][A])%mod;dp[i][B][A] = (dp[i][B][A]+mod - dp[i-1][C][B])%mod;dp[i][A][C] = (dp[i][A][C]+mod - dp[i-1][B][A])%mod;dp[i][C][A] = (dp[i][C][A]+mod - dp[i-1][B][C])%mod;dp[i][B][C] = (dp[i][B][C]+mod - dp[i-1][A][B])%mod;dp[i][C][B] = (dp[i][C][B]+mod - dp[i-1][A][C])%mod;}}}ll ans = 0;for(int j = 1; j<=49; j++) {for(int k = 1; k<=49; k++) {ans = (ans + dp[n][j][k])%mod; }}printf("%lld\n",ans);return 0 ;} /* 4 1 1 2 3 3 1 1 1 2*/?
AC代碼2:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair using namespace std; const int MAX = 2e5 + 5; ll dp[505][55][55],dpp[MAX]; bool bk[55][55][55]; const ll mod = 1e9 + 7; int main() {int n,q;cin>>n>>q;for(int x,y,z,i = 1; i<=q; i++) {scanf("%d%d%d",&x,&y,&z);bk[x][y][z]=1; bk[x][z][y]=1;bk[y][x][z]=1; bk[y][z][x]=1;bk[z][x][y]=1; bk[z][y][x]=1;}for(int i = 1; i<=2; i++) {for(int j = 1; j<=49; j++) {for(int k = 1; k<=49; k++) {dp[i][j][k] = 1;}}}for(int i = 3; i<=n; i++) {for(int j = 1; j<=49; j++) {for(int k = 1; k<=49; k++) {for(int l = 1; l<=49; l++) {if(bk[j][k][l]) continue ;dp[i][j][k] += dp[i-1][l][j];dp[i][j][k] %= mod;}}}}ll ans = 0;for(int j = 1; j<=49; j++) {for(int k = 1; k<=49; k++) {ans = (ans + dp[n][j][k])%mod; }}printf("%lld\n",ans);return 0 ;} /* 4 1 1 2 3 3 1 1 1 2*/?
總結
以上是生活随笔為你收集整理的【牛客 - 369A】小D的剧场(线性dp)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【FZU - 2202】犯罪嫌疑人(思维
- 下一篇: STMGR.EXE - STMGR是什么