Description
给你一个有 $n$ 个节点, $m$ 条边的 DAG 。
要求你在途中选择一条路径,可以只包含一个点,求有多少条路径满足路径上的点的编号积为平方数。
Solution
发现一个数若是完全平方数则它的每一个质因子的次数都是偶数。
于是我们可以对于每一个数分解质因数,然后 状压 DP 即可。
但是 90 以内的质数有 24 个,但是不要紧,因为因子里含有大于 45 的质数的数最多只有一个,就是它本身。
因为 45 以内的质数只有 14 个,我们就可以进行状压 DP 了。
设 $f[i][S]$ 表示当前在第 $i$ 个点,质因子状态为 $S$ 的路径条数。
对于次数大于 2 的,我们显然只需要记录下它的次数模 2 的值即可,因此 $S$ 是一个 01 串。
用 BFS 转移即可,起点选取所有入度为 0 的节点。
注意建边的时候不要建起点或终点的编号为大于 45 的质数的边。
时间复杂度 $O(2^{14} n^2)$ ,具体细节见代码部分。
Code
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 
 | #include <cstdio>#define maxN 100
 #define maxM 8010
 struct node{ long long x, y, g; } b[maxM];
 long long f[maxN][1 << 15], val[maxN], dl[maxN], rd[maxN], h[maxN], a[maxN];
 long long prime[15];
 long long len = 0, n = 0, m = 0;
 void ins (long long x, long long y)
 {
 len++;
 b[len].x = x;
 b[len].y = y;
 b[len].g = h[x];
 h[x] = len;
 }
 bool pd (long long x)
 {
 if(x < 2)
 {
 return false;
 }
 for(long long i = 2;i <= x - 1; i++)
 {
 if(!(x % i))
 {
 return false;
 }
 }
 return true;
 }
 void bfs ()
 {
 long long ma = (1 << 14) - 1;
 long long tou = 1, wei = 1;
 for(long long i = 1;i <= n; i++)
 {
 if(!rd[i])
 {
 dl[wei] = i;
 wei++;
 }
 }
 while(tou != wei)
 {
 long long x = dl[tou];
 for(long long i = h[x];i;i = b[i].g)
 {
 long long y = b[i].y;
 if(a[y])
 {
 continue;
 }
 for(long long j = 0;j <= ma; j++)
 {
 f[y][j ^ val[y]] += f[x][j];
 }
 rd[y]--;
 if(!rd[y])
 {
 dl[wei] = y;
 wei++;
 if(wei >= maxN)
 {
 wei = 1;
 }
 }
 }
 tou++;
 if(tou >= maxN)
 {
 tou = 1;
 }
 }
 }
 int main ()
 {
 scanf("%lld %lld", &n, &m);
 for(long long i = 1;i <= n / 2; i++)
 {
 if(pd(i))
 {
 prime[++prime[0]] = i;
 }
 }
 for(long long i = n / 2 + 1;i <= n; i++)
 {
 if(pd(i))
 {
 a[i] = 1;
 }
 }
 for(long long i = 1;i <= n; i++)
 {
 if(a[i])
 {
 continue;
 }
 long long now = i;
 for(long long j = 1;j <= prime[0]; j++)
 {
 long long cc = 0;
 while(!(now % prime[j]))
 {
 cc ^= 1;
 now /= prime[j];
 }
 if(cc)
 {
 val[i] |= (1 << (j - 1));
 }
 }
 }
 for(long long i = 1;i <= m; i++)
 {
 long long x = 0, y = 0;
 scanf("%lld %lld", &x, &y);
 if(a[x] || a[y])
 {
 continue;
 }
 rd[y]++;
 ins(x, y);
 }
 for(long long i = 1;i <= n; i++)
 {
 if(!a[i])
 {
 f[i][val[i]] = 1;
 }
 }
 bfs();
 long long ans = 0;
 for(long long i = 1;i <= n; i++)
 {
 ans += f[i][0];
 }
 printf("%lld", ans);
 return 0;
 }
 
 |