P5188题解
前言:
在写这道题的时候踩了一个大坑,题目要求要在第
虽然 yukimianyan 大佬的题解思路写的已经非常清楚了,但我觉得代码有一点看不懂,于是决定用相同的思路再写一篇。
科技:
矩阵乘法、快速幂
思路:
首先不考虑买食材的限制,设
则有:
而看到
首先一个
枚举集合
则此时的
最后由矩阵乘法的结合律可知:
时间复杂度
代码:
//建议定义新矩阵时将其数组无脑memset 防止出错
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 30,M = 510,mod = 5557;
int n,m,T,l,a,b,c,ans,bx[410];
string s;
struct edge{int u,v,w;} g[M];
struct matrix{int n,m,s[N << 1][N << 1];} bgn,base,tmp;
matrix operator *(matrix x,matrix y)
{
matrix ret;
ret.n = x.n,ret.m = y.m;
memset(ret.s,0,sizeof(ret.s));
for(int i = 1;i <= x.n;i++)
for(int j = 1;j <= y.m;j++)
for(int k = 1;k <= x.m;k++)
ret.s[i][j] = (ret.s[i][j] + x.s[i][k] * y.s[k][j] % mod) % mod;
return ret;
}
int popcount(int x)
{
int ret = 0;
for(int i = 1;i <= 8;i <<= 1) if(x & i) ret++;
return ret;
}
int v()
{
int ret = 0;
l = s.length();
for(int i = 0;i < l;i++) ret |= bx[s[i]];
return ret;
}
void init(int s)
{
memset(base.s,0,sizeof(base.s));
base.s[n + 1][2 * n + 1] = base.s[2 * n + 1][2 * n + 1] = 1;
for(int i = 1;i <= n;i++) base.s[i + n][i] = 1;
for(int i = 1;i <= m;i++)
{
base.s[g[i].u + n][g[i].v + n] = 1;
if((g[i].w & s) == g[i].w) base.s[g[i].u][g[i].v + n] = 1;
}
}
matrix ksm(matrix x,int y)
{
matrix ret;
ret.n = ret.m = 2 * n;
memset(ret.s,0,sizeof(ret.s));
for(int i = 1;i <= 2 * n;i++) ret.s[i][i] = 1;
while(y)
{
if(y & 1) ret = ret * x;
x = x * x;
y >>= 1;
}
return ret;
}
//BJMP
int main()
{
// freopen("data.in","r",stdin);
bx['B'] = 1,bx['J'] = 2,bx['M'] = 4,bx['P'] = 8;
cin >> n >> m;
for(int i = 1;i <= m;i++)
{
cin >> a >> b >> s;
c = v();
g[i] = (edge){a,b,c};
}
cin >> T;
//bgn就是T1
memset(bgn.s,0,sizeof(bgn.s));
bgn.n = 1,bgn.m = base.n = base.m = 2 * n + 1;
bgn.s[1][1] = 1;
for(int i = 1;i <= m;i++) if(g[i].u == 1) bgn.s[1][g[i].v + n] = 1;
for(int i = 15;i >= 0;i--)
{
init(i);
tmp = bgn * ksm(base,T);
a = tmp.s[1][n * 2 + 1];
if(popcount(i) & 1) ans = (ans - a + mod) % mod;
else ans = (ans + a) % mod;
}
cout << ans << endl;
return 0;
}