华中校赛 14th
https://www.nowcoder.com/acm/contest/106#question
A
分类讨论
#include<bits/stdc++.h> using namespace std ; #define LL long long int a[100010] ; int d[100010] ; vector< int > v[100010] ; void dfs( int id , int fa , int c ){ d[id] = c ; for( int i = 0 ; i < v[id].size() ; i++ ){ if( v[id][i] == fa ) continue ; dfs( v[id][i] , id , 3 - c ) ; } } int main(){ int T ; cin >> T ; while( T-- ){ int n ; scanf( "%d" , &n ) ; for( int i = 1 ; i <= n ; i++ ) v[i].clear() ; for( int i = 1 ; i <= n - 1 ; i++ ){ int a , b ; scanf( "%d%d" , &a , &b ) ; v[a].push_back( b ) ; v[b].push_back( a ) ; } dfs( 1 , 0 , 1 ) ; LL b , w ; b = 0 ; w = 0 ; for( int i = 1 ; i <= n ; i++ ) if ( d[i] == 1 ) b++ ; else w++ ; LL ans = 0 ; if ( n & 1 ) { ans = 2 * ( b * b * w + w * w * b ) ; } else{ ans = b * b * b + w * w * w + b * b * w + w * w * b ; } printf( "%lld\n" , ans ) ; } return 0 ; }
B
等比数列
#include<bits/stdc++.h> using namespace std ; #define LL long long char s[100010] ; const LL mod = 1e9 + 7 ; LL two[100010] ; LL pow_mod( LL a , LL b ){ a %= mod ; LL ans = 1 ; while( b ){ if ( b & 1 ) { ans *= a ; ans %= mod ; } a *= a ; a %= mod ; b >>= 1 ; } return ans ; } LL inv_mod( LL x ){ return pow_mod( x , mod - 2 ) ; } int main(){ int k ; cin >> k ; scanf( "%s" , s ) ; two[0] = 1 ; for( int i = 1 ; i <= 100000 ; i++ ){ two[i] = two[i - 1] * 2 ; two[i] %= mod ; } LL ans = 0 ; int len = strlen( s ) ; for( int i = 0 ; i < len ; i++ ){ if ( s[i] == '0' || s[i] == '5' ){ ans += two[i] ; ans %= mod ; } } LL q = two[len] ; if ( q == 1 ) { ans *= k ; ans %= mod ; } else{ LL res = pow_mod( q , k ) ; res-- ; if ( res < 0 ) res += mod ; ans *= res ; ans %= mod ; q-- ; if ( q < 0 ) q += mod ; ans *= inv_mod( q ) ; ans %= mod ; } cout << ans << endl ; return 0 ; }
C
并查集 (不带子树转移版)
有四种操作
1 u v 合并u,v所在的并查集
2 u 将u从其所在的并查集中分离出来
3 u 询问u所在并查集的大小
4 u v 询问u,v是否在一个并查集内
#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define pii pair<int, int> #define pb push_back #define mk make_pair #define fi first #define se second #define ALL(A) A.begin(), A.end() #define sqr(x) ((x)*(x)) #define sc(x) scanf("%d", &x) #define pr(x) printf(">>>"#x":%d\n", x) #define fastio ios::sync_with_stdio(0),cin.tie(0) #define frein freopen("in.txt", "r", stdin) #define freout freopen("out.txt", "w", stdout) #define debug cout<<">>>STOP"<<endl template<class T> T gcd(T a, T b) { if (!b) { return a; } return gcd(b, a % b); } const int maxn = 2e5 + 10; int par[maxn], hs[maxn]; int sz[maxn]; int cnt; void init(int n) { for (int i = 0; i <= n; i++) { par[i] = i, hs[i] = i, sz[i] = 1; } } int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); } void unite(int x, int y) { x = find(x); y = find(y); if (x != y) { par[x] = y, sz[y] += sz[x]; } } void del(int x) { sz[find(hs[x])]--; hs[x] = ++cnt; } int main() { int T, kase = 1; sc(T); while (T--) { printf("Case #%d:\n", kase++); int n, q; sc(n); sc(q); init(n + q); cnt = n; for (int i = 0; i < q; i++) { int op; sc(op); if (op == 1) { int u, v; sc(u); sc(v); unite(hs[u], hs[v]); } else if (op == 2) { int u; sc(u); del(u); } else if (op == 3) { int u; sc(u); int ans = sz[find(hs[u])]; printf("%d\n", ans); } else { int u, v; sc(u); sc(v); if (find(hs[u]) == find(hs[v])) { printf("YES\n"); } else { printf("NO\n"); } } } } return 0; }
F
冒泡排序变种
#include<bits/stdc++.h> typedef long long ll; using namespace std; const ll mod = 1e9 + 9; int num[100005]; int number[100005]; int visit[100005]; vector<int> now[100005]; int pop = 0; int ans[100005]; int main() { int n; int k; cin >> n >> k; int cur = 0; for (int i = 1; i <= n; i++) { scanf("%d", &num[i]); ans[i] = num[i]; } sort(ans + 1, ans + 1 + n); if (k == 0) { for (int i = 1; i <= n; i++) { if (num[i] != ans[i]) { cout << i << endl; return 0; } } cout << -1 << endl; return 0; } for (int i = 1; i <= n; i++) { if (visit[i]) { continue; } ++pop; cur = 0; for (int j = i; j <= n; j += k) { if (!visit[j]) { now[pop].push_back(num[j]); //cout<<num[j]<<" "<<j<<" "; } } //cout<<endl; sort(now[pop].begin(), now[pop].end()); for (int j = i; j <= n; j += k) { if (!visit[j]) { number[j] = now[pop][cur++]; visit[j] = 1; } } } for (int i = 1; i <= n; i++) { if (number[i] != ans[i]) { cout << i << endl; return 0; } } cout << -1 << endl; return 0; }
G
反推是否符合垂心 重心 内心 外心
x=[0,0,0,0]; y=[0,0,0,0]; def dOt(x0,y0,x1,y1): return x0*x1+y0*y1; def cRoss(x0,y0,x1,y1): return x0*y1-x1*y0; def lEnth2(x,y): return x*x+y*y; def check0(): n=[0,0,0]; for i in range(3): n[i]=cRoss(x[(i+1)%3]-x[i],y[(i+1)%3]-y[i],x[3]-x[i],y[3]-y[i]); if (n[0]<0 and n[1]<0 and n[2]<0) or (0<n[0] and 0<n[1] and 0<n[2]): return 1; else: return 0; def check1(): for i in range(3): if dOt(x[i]-x[3],y[i]-y[3],x[(i+2)%3]-x[(i+1)%3],y[(i+2)%3]-y[(i+1)%3])!=0: return 0; return 1 def check2(): n=[0,0]; for i in range(3): n[0]=abs(cRoss(x[(i+1)%3]-x[i],y[(i+1)%3]-y[i],x[3]-x[i],y[3]-y[i])); n[1]=abs(cRoss(x[(i+2)%3]-x[i],y[(i+2)%3]-y[i],x[3]-x[i],y[3]-y[i])); if n[0]!=n[1]: return 0; if check0()==1: return 1; else: return 0; def check3(): s=[0,0,0]; l=[0,0,0]; for i in range(3): s[i]=abs(cRoss(x[i]-x[3],y[i]-y[3],x[(i+1)%3]-x[3],y[(i+1)%3]-y[3])); l[i]=lEnth2(x[(i+1)%3]-x[i],y[(i+1)%3]-y[i]); for i in range(3): if s[i]*s[i]*l[(i+1)%3]!=s[(i+1)%3]*s[(i+1)%3]*l[i]: return 0; if check0()==1: return 1; else: return 0; def check4(): d=[0,0,0]; for i in range(3): d[i]=lEnth2(x[i]-x[3],y[i]-y[3]); if d[0]!=d[1] or d[1]!=d[2] or d[2]!=d[0]: return 0; return 1 for i in range(4): x[i],y[i]=map(int,input().split()); if check1()==1 or check2()==1 or check3()==1 or check4()==1: print("Yes"); else: print("No");
I
单调队列 O(n)可以处理处每个点的贡献
注意在push的时候一侧要是严格的 另一侧要是不严格的 比如先>= 后> 因为这样才是全部情况 如果全是严格则缺少情况 全是不严格则有重复情况
(即一个区间应只有一个最大值最小值有贡献 如果有多个最大值最小值也只能算一次)
#include<bits/stdc++.h> using namespace std; #define LL long long const int maxn = 1000000 + 50; int a[maxn], l[maxn], r[maxn]; inline void scan(int &a) { a = 0; char c; while (c = getchar(), !isdigit(c)); a = c - '0'; while (c = getchar(), isdigit(c)) { a = a * 10 + c - '0'; } } int main() { int n; while (scanf("%d", &n) != EOF) { LL res = 0; for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 1; i <= n; i++) { l[i] = r[i] = i; } for (int i = 2; i <= n; i++) { int cur = i; while (cur > 1 && a[i] >= a[cur - 1]) { cur = l[cur - 1]; } l[i] = cur; } for (int i = n - 1; i >= 1; i--) { int cur = i; while (cur < n && a[i] > a[cur + 1]) { cur = r[cur + 1]; } r[i] = cur; } for (int i = 1; i <= n; i++) { res += (LL)a[i] * (LL)(i - l[i] + 1) * (LL)(r[i] - i + 1); } for (int i = 1; i <= n; i++) { l[i] = r[i] = i; } for (int i = 2; i <= n; i++) { int cur = i; while (cur > 1 && a[i] <= a[cur - 1]) { cur = l[cur - 1]; } l[i] = cur; } for (int i = n - 1; i >= 1; i--) { int cur = i; while (cur < n && a[i] < a[cur + 1]) { cur = r[cur + 1]; } r[i] = cur; } for (int i = 1; i <= n; i++) { res -= (LL)a[i] * (LL)(i - l[i] + 1) * (LL)(r[i] - i + 1); } printf("%lld\n", res); } return 0; }
J
BFS
#include<bits/stdc++.h> typedef long long ll; using namespace std; const ll mod = 1e9 + 9; int dp[1000005]; void init() { dp[1] = 1, dp[2] = 1; for (int i = 3; i <= 1000000; i++) { dp[i] = dp[i - (i & (-i))] + 1; } } int visit[1000005]; queue<pair<int, int> > que; int main() { init(); int a, b; cin >> a >> b; int anser = INT_MAX; que.push(make_pair(a, 0)); while (!que.empty()) { int now = que.front().first; visit[now] = 1; int cur = que.front().second; //cout<<now<<" "<<cur<<endl; que.pop(); if (now == b) { cout << cur << endl; return 0; } if (!visit[now - 1]) { que.push(make_pair(now - 1, cur + 1)); visit[now - 1] = 1; } if (!visit[now + 1]) { que.push(make_pair(now + 1, cur + 1)); visit[now + 1] = 1; } if (!visit[now + dp[now]]) { que.push(make_pair(now + dp[now], cur + 1)); visit[now + dp[now]] = 1; } if (!visit[now - dp[now]]) { que.push(make_pair(now - dp[now], cur + 1)); visit[now - dp[now]] = 1; } } return 0; }
K
二分答案
#include<bits/stdc++.h> using namespace std ; int a[100010] ; #define LL long long int main(){ int n , k ; cin >> n >> k ; for( int i = 1 ; i <= n - 1 ; i++ ) scanf( "%d" , &a[i] ) ; LL l , r ; l = 0 ; r = 1e11 ; while( l + 1 < r ){ LL mid = ( l + r ) >> 1 ; LL sum = 0 ; int cnt = 1 ; for( int i = 1 ; i <= n - 1 ; i++ ){ if ( a[i] > mid ) { cnt += 0x3f3f3f3f ; break ; } sum += a[i] ; if ( sum > mid ){ cnt++ ; sum = a[i] ; } } if ( cnt > k ) l = mid ; else r = mid ; } cout << r << endl ; return 0 ; }
L
倒着搜索
#include<queue> #include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn = 2e3 + 10; const int maxm = 1e5 + 10; struct coord { int x, y; } tmp, nxt; queue<coord>q; int T, m, res; int x[maxm], y[maxm], ans[maxn]; int state[maxn][maxn]; int dir[4][2] = {{0, -1}, {0, 1}, { -1, 0}, {1, 0}}; void bfs(int x, int y) { state[tmp.x = x][tmp.y = y] = 2; //给所有大空地的地方打上标记 相当于并查集 res--, q.push(tmp); //剩下的数目-1 进行BFS while (!q.empty()) { tmp = q.front(); q.pop(); for (int i = 0; i < 4; i++) { nxt.x = tmp.x + dir[i][0]; //目标点的横纵坐标 nxt.y = tmp.y + dir[i][1]; if (nxt.x < 0 || nxt.x > 2000 || nxt.y < 0 || nxt.y > 2000) //如果这个点不符合条件 { continue; } if (state[nxt.x][nxt.y] != 0) //如果这个点是树 { continue; } state[nxt.x][nxt.y] = 2; res--; q.push(nxt); } } } bool check(int x, int y) { for (int i = 0; i < 4; i++) { int xx = x + dir[i][0], yy = y + dir[i][1]; if (xx < 0 || xx > 2000 || yy < 0 || yy > 2000) { continue; } if (state[xx][yy] == 2) { return 1; } } return 0; } int main() { scanf("%d", &m); for (int i = 1; i <= m; i++) { scanf("%d%d", &x[i], &y[i]); x[i] += 1000, y[i] += 1000; //避免负数 往右下移动1000 state[x[i]][y[i]] = 1; //表示该坐标是树 } res = 2001 * 2001 - m; //减去2001*2001剩下的不是树的点 bfs(0, 0); //减去所有没有被树包围的点 for (int i = m; i; i--) { ans[i] = res++; state[x[i]][y[i]] = 0; if (check(x[i], y[i])) //如果这个树的四连通块有一个属于大空地 就把这个树连通的连通块全部BFS成大空地 { bfs(x[i], y[i]); } } for (int i = 1; i <= m; i++) { printf("%d\n", ans[i]); } return 0; }