Solution
$jzy$大佬用了给的原根的信息,加上矩阵快速幂150行QAQ
然而$yuli$大佬的做法不仅好懂,代码只有50行!
快速幂的思想,把m看成要组成的区间总长度,每次将两段组合得到新的长度。
定义$g[i]$表示当前x为$i$时的方案数,用来最后计算期望,在快速幂中相当于ans,定义$f[i]$代表a,是初始要用来组合的长度为1的方案,再用一个辅助数组转移即可。
Code
#include<bits/stdc++.h> #define MOD 1000000007 #define LL long long using namespace std; LL mpow(LL a, LL b) { LL ans = 1; for(; b; b >>= 1, a = a * a % MOD) if(b & 1) ans = ans * a % MOD; return ans; } int n, m, mod, a; LL f[1005], fz[1005], g[1005]; int main() { freopen("rand.in", "r", stdin); freopen("rand.out", "w", stdout); scanf("%d%d%d", &n, &m, &mod); for(int i = 1; i <= n; i ++) scanf("%d", &a), f[a] ++; g[1] = 1; int M = m; while(m) { if(m % 2) { for(int i = 1; i < mod; i ++) fz[i] = 0; for(int i = 1; i < mod; i ++) for(int j = 1; j < mod; j ++) fz[i * j % mod] = (fz[i * j % mod] + 1ll * g[i] * f[j]) % MOD; for(int i = 1; i < mod; i ++) g[i] = fz[i]; } for(int i = 1; i < mod; i ++) fz[i] = 0; for(int i = 1; i < mod; i ++) for(int j = 1; j < mod; j ++) fz[i * j % mod] = (fz[i * j % mod] + 1ll * f[i] * f[j]) % MOD; for(int i = 1; i < mod; i ++) f[i] = fz[i]; m >>= 1; } LL ans = 0; for(int i = 1; i <= mod; i ++) ans = (ans + 1ll * g[i] * i) % MOD; ans = ans * mpow(mpow(n, M), MOD - 2) % MOD; printf("%lld", ans); return 0; }
Solution
完全没想到是带权并查集!!
网上大佬讲解的很好!写的时候细节也比较多,对带权并查集理解深了一层了QAQ想不通的一点就是排序如果按二维排就会错一个点??
Code
#include<bits/stdc++.h> #define LL long long using namespace std; inline LL read() { LL x = 0; int t = 0; char ch = getchar(); while(!isdigit(ch)) t |= (ch == '-'), ch = getchar(); while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * (t ? -1 : 1); } struct Node { int x, y; LL w; } a[100005]; bool cmp1(Node a, Node b) { return a.x < b.x; } bool cmp2(Node a, Node b) { return a.y < b.y; } LL fx[100005], fy[100005], wx[100005], wy[100005]; int findx(int x) { if(fx[x] == x) return fx[x]; int hx = findx(fx[x]); wx[x] += wx[fx[x]]; return fx[x] = hx; } bool checkx(int x, int y, LL w) { int hx = findx(x), hy = findx(y); if(hx == hy) return wx[x] == wx[y] + w; fx[hx] = hy; wx[hx] = wx[y] + w - wx[x]; return 1; } int findy(int x) { if(fy[x] == x) return fy[x]; int hy = findy(fy[x]); wy[x] += wy[fy[x]]; return fy[x] = hy; } bool checky(int x, int y, LL w) { int hx = findy(x), hy = findy(y); if(hx == hy) return wy[x] == wy[y] + w; fy[hx] = hy; wy[hx] = wy[y] + w - wy[x]; return 1; } int R, C, n; LL Min[100005], Max[100005]; bool work() { R = read(), C = read(); n = read(); memset(Min, 127, sizeof(Min)); memset(Max, 127, sizeof(Max)); int p = 1; for(int i = 1; i <= n; i ++) { a[i].x = read(), a[i].y = read(), a[i].w = read(); if(a[i].w < 0 || (R * C <= 12 && a[i].w >= 3 && R != 1)) p = 0; } if(!p) return 0; for(int i = 1; i <= R; i ++) fx[i] = i, wx[i] = 0; for(int i = 1; i <= C; i ++) fy[i] = i, wy[i] = 0; sort(a + 1, a + 1 + n, cmp1); for(int i = 1; i < n; i ++) { if(a[i].x == a[i + 1].x && !checky(a[i].y, a[i + 1].y, a[i + 1].w - a[i].w)) return 0; } sort(a + 1, a + 1 + n, cmp2); for(int i = 1; i < n; i ++) { if(a[i].y == a[i + 1].y && !checkx(a[i].x, a[i + 1].x, a[i + 1].w - a[i].w)) return 0; } for(int i = 1; i <= n; i ++) { int x = findx(a[i].x); Min[x] = min(Min[x], a[i].w + wx[a[i].x]); } for(int i = 1; i <= R; i ++) { int x = findx(i); Max[x] = min(Max[x], -wx[i]); } for(int i = 1; i <= R; i ++) { if(Min[i] + Max[i] < 0 && fx[i] == i) return 0; } return 1; } int main() { freopen("then.in", "r", stdin); freopen("then.out", "w", stdout); int T; scanf("%d", &T); while(T --) { if(work()) puts("Yes"); else puts("No"); } return 0; }
Solution
乍一看怎么那么像聪聪与可可??然而这实际上是面具下隐藏着的小模拟!!!QAQ
仔细读读题发现自己的移动根本是没有用的,因为这一步除了使距离拉近一步外什么都没有做,不如给自己回蓝或者尽量去打香港记者,因为此时的距离的贡献一定比以后优。
然后就是能打就打,不能打就回蓝。
香港记者走的永远是受伤害最小的地方,因此要比较三个方位,然而就是这里让100分打水漂了QAQ
因为在最后他也可以只走一步,不一定一定要走两步,所以下面的写法就很精髓了QAQ
for(int i = 1; i <= 2; i++) { if(tx == 0 && ty == 0) break; if(tx <= ty) ty--; else tx--; }
Code
#include<bits/stdc++.h> #define LL long long using namespace std; inline int read() { int x = 0; int t = 0; char ch = getchar(); while(!isdigit(ch)) t |= (ch == '-'), ch = getchar(); while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * (t ? -1 : 1); } int a, b; int a1, a2, b1, b2, c, d; inline LL Min(LL a, LL b) { return a < b ? a : b; } void work() { a1 = read(), b1 = read(), a2 = read(), b2 = read(), c = read(), d = read(); int tx = abs(a1 - a2), ty = abs(b1 - b2); int flag = 1; while(1) { if(d <= 0) break; if(tx == 0 && ty == 0) { flag = 0; break; } if(c < a) c += b; else c -= a, d -= tx * tx + ty * ty; if(d <= 0) break; for(int i = 1; i <= 2; i++) { if(tx == 0 && ty == 0) break; if(tx <= ty) ty--; else tx--; } } if(flag) printf("NAIVE "); else printf("SIMPLE "); } int main() { freopen("do.in", "r", stdin); freopen("do.out", "w", stdout); int T; T = read(); a = read(), b = read(); while(T --) { work(); } return 0; }