Alphabet Soup
题意:在圆上给m个点,告诉你角度,现在有n种颜色,问有多少种涂色方案。
和典型的项链那道题相比,唯一附加的条件就是角度。
于是,我们可以求得角度差的循环节的长度,然后每次旋转的限制是:必须旋转循环节长度的倍数。
求循环节长度用kmp的fail数组, len - fail[len] 就是循环节长度。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 const int mod = 1e8 + 7; 5 const int maxn = 360010; 6 int a[maxn], b[maxn]; 7 int f[maxn]; 8 void getf(int m){ 9 f[0] = f[1] = 0; 10 for(int i = 1; i < m; i++){ 11 int j = f[i]; 12 while(j && b[i] != b[j]) j = f[j]; 13 f[i + 1] = b[i] == b[j] ? j + 1 : 0; 14 } 15 } 16 LL quickpow(LL a, LL b, LL mod){ 17 LL temp = a % mod, res = 1; 18 while(b){ 19 if(b & 1) res = res * temp % mod; 20 b >>= 1; 21 temp = temp * temp % mod; 22 } 23 return res; 24 } 25 int main(){ 26 //freopen("in.txt", "r", stdin); 27 int n, m; 28 while(scanf("%d %d", &n, &m) && (n + m) > 0){ 29 for(int i = 0; i < m; i++){ 30 scanf("%d", &a[i]); 31 } 32 sort(a, a + m); 33 for(int i = 0; i < m; i++){ 34 b[i] = a[(i + 1) % m] - a[i]; 35 if(b[i] < 0) b[i] += 360000; 36 } 37 getf(m); 38 int cir = m - f[m]; 39 //cout<<cir<<endl; 40 // int cnt; 41 // if(m % cir == 0) cnt = m / cir; 42 // else cnt = m; 43 LL ans = 0; 44 int rt = 0; 45 for(int i = 0; i < m; i++){ 46 if(i % cir == 0) { 47 ans = ans + quickpow(n, __gcd(i, m), mod); 48 rt++; 49 if(ans >= mod) ans %= mod; 50 } 51 } 52 ans = ans * quickpow(rt, mod - 2, mod) % mod; 53 printf("%lld ", ans); 54 } 55 }