今天下午BZ在维护,我就用同学拿到的数据(权限号好爽)跑过了,等会晚上再交吧。这道题一看就是矩阵快速幂,最开始没有想到拆点的做法只想到了拆边,复杂度直接爆掉了。所以我们把每个点拆成3个,分别表示长度为1,2,3的边该连到这个点的哪个分身(不想画图了以后自己忘了自己YY吧)。然后开始矩阵快速幂,里面可以顺便处理出长度为L时,0~L的总方案数。最开始想到的比较蠢的做法是二分。强加了一个LOG,肯定是过不了的(这道题有56个点),所以我们预处理出2的logk*3次幂的矩阵,然后像倍增一样倒着加进去。
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 using namespace std; 8 const int N = 43; 9 const int M = 1003; 10 const double LOG = log(3*1000000000000000000LL); 11 struct rp { 12 long long w[N*3][N*3]; 13 }need[64],ans; 14 long long st[3*N]; 15 int n,m; 16 unsigned long long k; 17 bool flag = false; 18 inline rp cheng(rp a,rp b) { 19 rp c; 20 flag = false; 21 memset(c.w,0,sizeof(c.w)); 22 for(int i = 1 ; i <= n*3+1 ; ++i) 23 for(int k = 1 ; k <= n*3+1 ; ++k) 24 if(!a.w[i][k]) 25 for(int j = 1 ; j <= n*3+1 ; ++j) { 26 c.w[i][j] += a.w[i][k]*b.w[k][j]; 27 if(c.w[i][j] < 0) { 28 flag = true; 29 return a; 30 } 31 } 32 return c; 33 } 34 int main() { 35 scanf("%d%d",&n,&m); 36 cin >> k; 37 for(int i = 1 ; i <= m ; ++i) { 38 int x,y,d; 39 scanf("%d%d%d",&x,&y,&d); 40 if(d==1) need[0].w[y][x]++,st[y]++; 41 if(d==2) need[0].w[y+n][x]++,st[y+n]++; 42 if(d==3) need[0].w[y+2*n][x]++,st[y+2*n]++; 43 } 44 for(int i = 1 ; i <= n ; ++i) need[0].w[i][i+n]++; 45 for(int i = 1 ; i <= n ; ++i) need[0].w[i+n][i+2*n]++; 46 for(int i = 1 ; i <= n ; ++i) need[0].w[3*n+1][i] = 1; 47 for(int i = 1 ; i <= 3*n+1 ; ++i) ans.w[i][i] = 1; 48 need[0].w[3*n+1][3*n+1] = 1; 49 unsigned long long kk = 1; 50 int cnt = 0; 51 do { 52 kk<<=1; 53 if(kk>3*k) break; 54 cnt++; 55 need[cnt] = cheng(need[cnt-1],need[cnt-1]); 56 if(flag) { 57 cnt--; 58 break; 59 } 60 }while(1); 61 unsigned long long ans2 = 0; 62 for(int i = cnt ; i >= 0 ; --i) { 63 kk>>=1; 64 rp linshi = cheng(ans,need[i]); 65 if(flag) continue; 66 unsigned long long linshi2 = 0; 67 for(int i = 1 ; i <= 3*n+1 ; ++i) linshi2 += (linshi.w[3*n+1][i]*st[i]); 68 if(linshi2 < k) { 69 ans = linshi; 70 ans2 ^= kk; 71 } 72 } 73 if(ans2 > k*3) cout << -1; 74 else cout << ans2 + 1; 75 }
我跑得比唐宇豪慢啊慢啊。对了这道题开教会了我矩阵快速幂的常数优化,就是for i j k 的顺序换成for i k j然后判断第一个矩阵的i,k是不是为零,为零的话就直接continue掉。快了50倍呢。那个LOG不要管,是我判读爆没有的时候开始的乱搞。后来判断爆没有是看它是不是负数,还是比较靠谱。