平时二十一测
今天考的真的是惨,和爆零差不多了,果然很不稳定啊
第一题:
其实原根没什么,利用期望的性质就好了:权值*概率;
该怎么求最后的权值?
dp[ i ][ j ]表示选了i个数,凑出来是j的方案数, 很好转移dp[i + 1][j * ai%mod] += dp[ i ][ j ];
但是m的数据范围很明显是log,考虑二进制拆分,dp[ i ][j * k % mod] = dp[ i ][ j ] * dp[ i ][ k ], 利用乘法得到j*k%mod的方案数,但是这样是选了2*i个数,这样翻倍是不是很像快速幂;
把m拆位,然后像快速幂计算就好了;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int M = 1e5 + 5; #define ll long long const ll P = 1e9 + 7, Pb = 1e9 + 5; ll ksm(ll a, ll b, ll P){ ll ret=1; for(;b;b>>=1,a=a*a%P) if(b&1)ret=ret*a%P; return ret; } ll dp[33][1005], tmp[1005], ans[1005]; int main(){ freopen("rand.in","r",stdin); freopen("rand.out","w",stdout); int n, m, mod; scanf("%d%d%d", &n,&m, &mod); for(int i = 1; i <= n; i++){ int x; scanf("%d", &x); dp[0][x] ++; } ll Ans = 0; int logm = log2(m); for(int i = 1; i <= logm; i++) for(int j = 1; j < mod; j++) for(int k = 1; k < mod; k++){ dp[i][k * j % mod] = (dp[i][k * j % mod] + dp[i - 1][k] * dp[i - 1][j] % P) % P; } ans[1] = 1; for(int i = 0; i <= logm; i++) if(m & (1<<i)){ memset(tmp, 0, sizeof(tmp)); for(int j = 1; j < mod; j++) for(int k = 1; k < mod; k++) tmp[k * j % mod] = (tmp[k * j % mod] + ans[j] * dp[i][k] % P) % P; for(int j = 1; j < mod; j++ )ans[j] = tmp[j]; } for(int i = 1; i < mod; i++) Ans = (Ans + ans[i] * i % P) % P; ll t = ksm(n, m, P); t = ksm(t, 1e9 + 5, P); Ans = Ans * t % P; printf("%lld\n", Ans); }
第二题:
发现同行间,同列间的差值一定;
这个限制可以用带权并查集解决,判断合法;
处理非负数,可以用众多儿子推出某一行的最小值,然后选择儿子通向父亲边权最大的一条边,就可以得到儿子的最小值,判断>=0;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int M = 1e5 + 5; int fax[M], fay[M], rex[M], rey[M], dl[M], dx[M]; struct node{int x, y, w;}g[M]; bool cmp1(node A, node B){return A.x < B.x;} bool cmp2(node A, node B){return A.y < B.y;} int find_x(int x){ if(x == fax[x]) return x; int f = fax[x]; fax[x] = find_x(fax[x]); rex[x] += rex[f]; return fax[x]; } int find_y(int x){ if(x == fay[x]) return x; int f = fay[x]; fay[x] = find_y(fay[x]); rey[x] += rey[f]; return fay[x]; } bool union_x(int w, int f, int son){ int fx = find_x(son), fy = find_x(f); if(fx == fy && rex[son] != rex[f] + w) return 0; fax[fx] = fy, rex[fx] = w + rex[f] - rex[son]; return 1; } bool union_y(int w, int f, int son){ int fx = find_y(son), fy = find_y(f); if(fx == fy && rey[son] != rey[f] + w) return 0; fay[fx] = fy, rey[fx] = w + rey[f] - rey[son]; return 1; } bool solve(){ int R, C, n, x, y, d; bool fg = 0; scanf("%d%d%d", &R, &C, &n); for(int i = 1; i <= n; i++){ scanf("%d%d%d",&x,&y,&d); g[i] = (node){x, y, d}; if(d < 0) fg = 1; } if(fg) return 0; memset(dx, 127, sizeof(dx)); memset(dl, 127, sizeof(dl)); for(int i = 0; i <= R; i++) fax[i] = i, rex[i] = 0; for(int i = 0; i <= C; i++) fay[i] = i, rey[i] = 0; sort(g + 1, g + 1 + n, cmp1); for(int i = 1; i < n; i++) if(g[i].x == g[i + 1].x) if(!union_y(g[i].w - g[i+1].w, g[i].y, g[i+1].y)) return 0; sort(g + 1, g + 1 + n, cmp2); for(int i = 1; i < n; i++) if(g[i].y == g[i + 1].y) if(!union_x(g[i].w - g[i+1].w, g[i].x, g[i+1].x)) return 0; for(int i = 1; i <= n; i++){ int fx = find_x(g[i].x); dx[fx] = min(dx[fx], g[i].w + rex[g[i].x]); } for(int i = 1; i <= R; i++){ int fx = find_x(i); dl[fx] = min(dl[fx], -rex[i]); } for(int i = 1; i <= R; i++) if(fax[i] == i && dx[i] + dl[i] < 0) return 0; return 1; } int main(){ freopen("then.in","r",stdin); freopen("then.out","w",stdout); int T; scanf("%d", &T); while(T--){ if(!solve())puts("No"); else puts("Yes"); } //system("pause"); }
第三题:
是一道真水题,但是我看到题这么长就不想思考了,打了半天的dfs分都不分;
正解贪心:人逃是没有用的,怎么也跑不掉,决策就只有膜了;魔法师:会尽量减小x, y 差值中差值最大的,因为平方的缘故,然后暴力搞就好了
值得一提的是我英文单词又拼错了;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; int T, A, B, ok; inline int ab(int a){return a >= 0 ? a : -a;} int main(){ freopen("do.in","r",stdin); freopen("do.out","w",stdout); int x1, y1, x2, y2, c, d; scanf("%d%d%d", &T, &A, &B); while(T--){ scanf("%d%d%d%d%d%d", &x1, &y1, &x2, &y2, &c, &d); int opt = 0; while(1){ if(d <= 0) {puts("NAIVE");break;} if(x1 == x2 && y2 == y1) {puts("SIMPLE");break;} if(opt == 0){ if(c < A)c += B; else if(c >= A){ int dis = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2); d -= dis; c -= A; if(d <= 0) {puts("NAIVE");break;} } opt = 1; } else { if(opt == 1) opt = 2; else opt = 0; int res1 = ab(x1 - x2), res2 = ab(y1 - y2); if(res2 > res1) y2 += (y1 > y2 ? 1 : -1); else x2 += (x1 > x2 ? 1 : -1); } } } return 0; }