链接:https://ac.nowcoder.com/acm/contest/369/A
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
若你摘得小的星星 你将得到小的幸福
若你摘得大的星星 你将得到大的财富
若两者都能摘得 你将得到永远的愿望
摘星是罪孽的宽恕 摘星是夜晚的奇迹
抓住它吧 你所期望的那颗星
无法触及,因而耀眼
明明触及了,却还是耀眼
——《少女☆歌剧 Revue·Starlight》
题目描述
"我明白。"
作为这命运剧场永远的观众,小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=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正在推算有多少合法的序列,答案对 10^9+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
答案为49^3−6=117643
备注:
3≤n≤500,0≤q≤117649,1≤a,b,c≤49
题意:求一个序列中不含有不合法子序列的个数。
题解:排列组合,用dp解决,dp[i][r][j]的意思是:i为序列长度,r为序列倒数第二位,j为序列倒数第一位,a[][][]=1代表不合法,a[][][]=0代表合法,然后我们就可以推出递推式 dp[i][r][j]=dp[i][r][j]+(a[j[k][r]^1)*dp[i-1][k][r];异或是因为0表示合法,1表示不合法~~这样就可以写代码了,上代码(代码里还有细节解释):
#include <iostream>
#include <cstring>
using namespace std;
const int MAX = 666;
const int mod = 1e9+7;
int dp[MAX][66][66];
int a[MAX][66][66];
int main(){
int n,q;
cin >> n >> q;
dp[0][0][0]=1;//注意初始化为1
for (int i = 0; i < q;i++){
int x,y,z;
cin >> x >> y >> z;
a[x][y][z]=a[x][z][y]=a[y][x][z]=a[y][z][x]=a[z][x][y]=a[z][y][x]=1;//不合法标记为1
}
for (int i = 1; i <= n;i++){
for (int j = 1; j <= 49;j++){
for (int k = 0; k <= 49;k++){
for (int r = 0; r <= 49;r++){
dp[i][r][j]=(dp[i][r][j]+(a[j][k][r]^1)*dp[i-1][k][r])%mod;//递推式
}
}
}
}
int ans=0;
for (int i = 1; i <= 49;i++){
for (int j = 1; j <= 49;j++){
ans=(ans+dp[n][i][j])%mod;//最后两位的各种情况求和,因为没有带上最后两位进行dp求和,只求出最后两位每个情况有多少种,所以需要求和~~
}
}
cout << ans << endl;
return 0;
}