题干:

链接:​​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了、、【牛客 - 369A】小D的剧场(线性dp)_i++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

*/