CodeForces Educational Codeforces Round 51 (Rated for Div. 2)
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int N = 1e5 + 100; char s[N]; int main(){ int T; int low, upp, dig; scanf("%d", &T); while(T--){ scanf("%s", s); int len = strlen(s); low = upp = dig = 0; for(int i = 0; i < len; ++i){ if(islower(s[i])) low++; else if(isupper(s[i])) upp++; else dig++; } if(low == 0 && upp == 0){ s[0] = 'A'; s[1] = 'a'; } else if(low == 0 && dig == 0) s[0] = 'a', s[1] = '1'; else if(dig == 0 && upp == 0) s[0] = '1', s[1] = 'A'; else if(low == 0){ if(upp > 1) {for(int i = 0; i < len; ++i) if(isupper(s[i])) {s[i] = 'a'; break;};} else {for(int i = 0; i < len; ++i) if(isdigit(s[i])) {s[i] = 'a'; break;};} } else if(dig == 0){ if(upp > 1) {for(int i = 0; i < len; ++i) if(isupper(s[i])) {s[i] = '1'; break;};} else {for(int i = 0; i < len; ++i) if(islower(s[i])) {s[i] = '1'; break;};} } else if(upp == 0){ if(low > 1) {for(int i = 0; i < len; ++i) if(islower(s[i])) {s[i] = 'A'; break;};} else {for(int i = 0; i < len; ++i) if(isdigit(s[i])) {s[i] = 'A'; break;};} } printf("%s\n", s); } return 0; }
相邻2位gcd一定为1。
代码:
Copy #include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int N = 1e5 + 100; int main(){ LL l, r; scanf("%lld%lld", &l , &r); if((r-l+1)&1) puts("NO"); else { puts("YES"); for(LL i = l; i <= r; i += 2){ printf("%lld %lld\n", i, i+1); } } return 0; }
题意:将所有数分组,要求2个组的完美数的数量相等。
题解:
只有数量为1的数和数量大于2的数才会影响平衡。
数量为2的数,如果选1个放在左边,则另一个就会放在右边。
数量>2的数,就可以把他变成1个完美数+1个不完美数,或者是1个不完美数。
数量为一的数,一定是完美数。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int N = 1e5 + 100; int vis[N]; int a[N]; int ok[N]; int main(){ int n; scanf("%d", &n); for(int i = 1; i <= n; ++i){ scanf("%d", &a[i]); ++vis[a[i]]; } int n1 = 0, n2 = 0; for(int i = 1; i <= 100; ++i){ if(vis[i] == 1) ++n1; if(vis[i] > 2) ++n2; } if(n1 & 1){ if(n2){ puts("YES"); n2 = 1; n1 /= 2; for(int i = 1; i <= n; ++i){ if(vis[a[i]] >= 3 && n2){ printf("A"); n2--; } else if(vis[a[i]] == 1 && n1){ printf("A"); n1--; } else printf("B"); } } else { puts("NO"); } } else { n1 /= 2; puts("YES"); for(int i = 1; i <= n; ++i){ if(vis[a[i]] == 1 && n1){ printf("A"); n1--; } else printf("B"); } } return 0; }
题意:2×m的格子,求联通块为k的方案数。
题解:DP.
dp[i][k][z1][z2]代表的是处理到第i个位置,有k个联通块,上面颜色为z1,下面颜色为z2的方案数。
然后我们就可以枚举 dp[i-1]的方案,把值加到dp[i][k][z1][z2]上来。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = 998244353; const int N = 1e3+10; LL dp[N][N<<1][2][2]; int main(){ dp[1][1][0][0] = dp[1][1][1][1] = 1; dp[1][2][0][1] = dp[1][2][1][0] = 1; int n, m; scanf("%d%d", &n, &m); for(int i = 2; i <= n; ++i){ for(int k = 1; k <= m; ++k){ dp[i][k][0][0] = (dp[i-1][k][0][0] + dp[i-1][k][0][1] + dp[i-1][k][1][0] + dp[i-1][k-1][1][1]) % mod; dp[i][k][1][1] = (dp[i-1][k][1][1] + dp[i-1][k][0][1] + dp[i-1][k][1][0] + dp[i-1][k-1][0][0]) % mod; dp[i][k][0][1] = (dp[i-1][k-1][0][0] + dp[i-1][k-1][1][1] + dp[i-1][k][0][1]); dp[i][k][1][0] = (dp[i-1][k-1][0][0] + dp[i-1][k-1][1][1] + dp[i-1][k][1][0]); if(k > 1){ dp[i][k][0][1] += dp[i-1][k-2][1][0]; dp[i][k][1][0] += dp[i-1][k-2][0][1]; } dp[i][k][0][1] %= mod; dp[i][k][1][0] %= mod; } } // cout << dp[2][2][0][1] << " " << dp[2][2][1][0] << " " << dp[2][4][0][1] << " " << dp[2][4][1][0] << endl; LL ans = 0; ans = dp[n][m][0][0] + dp[n][m][1][1] + dp[n][m][1][0] + dp[n][m][0][1]; ans %= mod; cout << ans << endl; return 0; }
题意:问将一个字符串,分成若干段,要求每一段都的值都 <= l && <= r,求可行的方案数。
题解:字符串hash * 二分 + DP 或者 Z-function + DP。
方案数通过DP转移。那么我们就需要求出哪一段是可以转移到当前的。
如果需要大于L,那么就是往前走L-len步, 然后再判断这个位置开始的字符串可以不可以作为起点,不可以就往前走一步。
如果需要小于R,那么就是往前走R-len步,然后再判断这个位置开始的字符串是不是可以作为终点,不可以就往后走一步。
现在的问题就是怎么判断。
方法1,就是hash字符串之后,通过二分找到第一个hash值不相等的地方,然后再判断接来下字母的大小。
方法2,就是通过Z-function,找到每个位置能匹配的最大长度,如果不能完全匹配,那么就判断不匹配位置的字符大小。
接下来的问题就是前导0的问题。
定义sum[i]为到i为止方案数的前缀和,并且不包括有0可能作为前导出现的情况,也就是说当处理到a[i]的时候,只有当a[i+1]!=0的时候我们才会把东西放进去。
定义val[i]为i的方案数。
那么我们就可以避免前导0的情况了。
现在还需要考虑单独为0的情况,如果当前为‘0’,并且L = ‘0’,那么就可以 val[i] += val[i-1]。
代码1:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = 998244353; const int N = 1e6 + 100; char l[N], r[N], s[N]; LL sum[N]; LL v[N]; LL base = 397; int Mod = 1e9+7; ULL Hash[N], s_val[N], l_val[N], r_val[N]; int len1, len2, len3; void init(){ Hash[0] = 1; for(int i = 1; i < N; ++i) Hash[i] = (Hash[i-1] * base) % Mod; for(int i = 1; i <= len1; ++i) s_val[i] = (s_val[i-1] * base + s[i] - '0' + 1)%Mod; for(int i = 1; i <= len2; ++i) l_val[i] = (l_val[i-1] * base + l[i] - '0' + 1)%Mod; for(int i = 1; i <= len3; ++i) r_val[i] = (r_val[i-1] * base + r[i] - '0' + 1)%Mod; } ULL G1(int ll, int rr){ return (s_val[rr] - s_val[ll-1] * Hash[rr-ll+1]%Mod+Mod)%Mod; } ULL G2(int ll, int rr){ return l_val[rr]; } ULL G3(int ll, int rr){ return r_val[rr]; } bool check1(int lp){ if(lp < 1) return false; if(G1(lp, lp+len2-1) == G2(1,len2)) return true; int ll = 1, rr = len2; while(ll <= rr){ int mid = ll+rr >> 1; if(G1(lp, lp+mid-1) == G2(1,mid)) ll = mid+1; else rr = mid - 1; } return s[lp+ll-1] > l[ll]; } bool check2(int rp){ if(rp < 1) return true; if(G1(rp,rp+len3-1) == G3(1,len3)) return true; int ll = 1, rr = len3; while(ll <= rr){ int mid = ll+rr >> 1; if(G1(rp,rp+mid-1) == G3(1,mid)) ll = mid+1; else rr = mid-1; } return s[rp+ll-1] < r[ll]; } int lpos[N]; int rpos[N]; LL val[N]; int main(){ scanf("%s", s+1); scanf("%s", l+1); scanf("%s", r+1); len1 = strlen(s+1); len2 = strlen(l+1); len3 = strlen(r+1); init(); int ok = 0; if(len2 == 1 && l[1] == '0') ok = 1; sum[0] = 1; for(int i = 1; i <= len1; ++i){ sum[i] += sum[i-1]; if(ok && s[i] == '0') val[i] += val[i-1]; int lp = i - (len2-1); if(!check1(lp)) lp--; if(lp < 1) continue; int rp = i - (len3-1); if(!check2(rp)) rp++; if(rp < 1) rp = 1; if(lp < rp) continue; val[i] += sum[lp-1]; if(rp-2 >= 0) val[i] -= sum[rp-2]; val[i] = ((val[i] % mod) + mod ) % mod; if(s[i+1] != '0') sum[i] = (sum[i]+val[i]) % mod; } printf("%lld\n", val[len1]); return 0; } /* 156156748948919764684894891894874874891981 1 581684 */
代码2:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = 998244353; const int N = 1e6 + 100; char l[N], r[N], s[N]; LL sum[N]; LL v[N]; LL base = 397; int Mod = 1e9+7; ULL Hash[N], s_val[N], l_val[N], r_val[N]; int len1, len2, len3; int posl[N]; int posr[N]; int z[N*2]; char ss[N*3]; void init(){ strcpy(ss, l+1); ss[len2] = '#'; strcpy(ss+len2+1, s+1); int n = len1 + 1 + len2, j = 1; z[0] = n; int k; for(int i=1;i<n;i=k){ if(j < i) j = i; while (j < n && ss[j] == ss[j-i]) j++; z[i]=j-i; k=i+1; while (k+z[k-i]<j){ z[k]=z[k-i];k++; } } for(int i = 1; i <= len1; ++i) posl[i] = z[len2+i]; strcpy(ss, r+1); ss[len3] = '#'; strcpy(ss+len3+1, s+1); n = len1 + 1 + len3; z[0] = n; j = 1; for(int i=1 ;i < n; i=k){ if(j < i) j = i; while (j < n && ss[j] == ss[j-i]) j++; z[i]=j-i; k = i+1; while (k+z[k-i]<j){ z[k]=z[k-i];k++; } } for(int i = 1; i <= len1; ++i) posr[i] = z[len3+i]; } LL val[N]; bool check1(int p){ if(p < 1) return false; if(posl[p] == len2) return true; return s[p+posl[p]] >= l[posl[p]+1]; } bool check2(int p){ if(p < 1) return true; if(posr[p] == len3) return true; return s[p+posr[p]] <= r[posr[p]+1]; } int main(){ scanf("%s", s+1); scanf("%s", l+1); scanf("%s", r+1); len1 = strlen(s+1); len2 = strlen(l+1); len3 = strlen(r+1); init(); int ok = 0; if(len2 == 1 && l[1] == '0') ok = 1; sum[0] = 1; for(int i = 1; i <= len1; ++i){ sum[i] += sum[i-1]; if(ok && s[i] == '0') val[i] += val[i-1]; int lp = i - (len2-1); if(!check1(lp)) lp--; if(lp < 1) continue; int rp = i - (len3-1); if(!check2(rp)) rp++; if(rp < 1) rp = 1; if(lp < rp) continue; val[i] += sum[lp-1]; if(rp-2 >= 0) val[i] -= sum[rp-2]; val[i] = ((val[i] % mod) + mod ) % mod; if(s[i+1] != '0') sum[i] = (sum[i]+val[i]) % mod; } printf("%lld\n", val[len1]); return 0; } /* 156156748948919764684894891894874874891981 1 581684 */
题意:问2点之间最短的距离。
题解:套路题。枚举边+lca。
需要注意到 m-n <= 20。
那么我们就可以枚举边了,我们先把所有的边加入进来的时候,用并查集维护联通块的信息,如果发现不加某条边也是联通的情况,就把这条边的编号存下来。
然后我们把存下来的边枚举一遍更新所有的答案。
然后在把所有存下来的边都ban掉,然后跑lca在更新一遍答案。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<LL,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int N = 1e5 + 100, M = 4e5+100; int pre[N]; int head[N], to[M], nt[M], ct[M], tot, ok[M]; void add(int u, int v, int w){ to[tot] = v; ct[tot] = w; nt[tot] = head[u]; head[u] = tot++; } int Find(int x){ if(x == pre[x]) return x; return pre[x] = Find(pre[x]); } pll p[N]; LL ans[N]; vector<int> vc; LL d[N][2]; void Dij(int u, int op){ priority_queue<pll, vector<pll>, greater<pll> > pq; d[u][op] = 0; pq.push(pll(0,u)); while(!pq.empty()){ int x = pq.top().se; LL dis = pq.top().fi; pq.pop(); if(d[x][op] > dis) continue; for(int i = head[x], v; ~i; i = nt[i]){ v = to[i]; if(ok[i]) continue; if(d[v][op] > d[x][op] + ct[i]){ d[v][op] = d[x][op] + ct[i]; pq.push(pll(d[v][op],v)); } } } } int anc[N][20]; LL sum[N]; int deep[N]; int Log = 20; void dfs(int o, int u){ deep[u] = deep[o] + 1; anc[u][0] = o; for(int i = 1; i < Log; ++i) anc[u][i] = anc[anc[u][i-1]][i-1]; for(int i = head[u],v; ~i; i = nt[i]){ v = to[i]; if(v == o || ok[i]) continue; sum[v] = sum[u] + ct[i]; dfs(u,v); } } int lca(int u, int v){ if(deep[u] > deep[v]) swap(u,v); int k = deep[v] - deep[u]; for(int i = Log-1; i >= 0; --i) if((k>>i)&1) v = anc[v][i]; if(u == v) return u; for(int i = Log-1; i >= 0; --i) if(anc[u][i] != anc[v][i]) u = anc[u][i], v = anc[v][i]; return anc[u][0]; } LL dis(int u, int v){ return sum[u]+sum[v] - 2*sum[lca(u,v)]; } int main(){ int n, m, q; scanf("%d%d", &n, &m); memset(head, -1, sizeof (head)); memset(ans, INF, sizeof(ans)); for(int i = 1; i <= n; ++i) pre[i] = i; int u,v,w; for(int i = 1; i <= m; ++i){ scanf("%d%d%d", &u, &v, &w); add(u,v,w); add(v,u,w); u = Find(u), v = Find(v); if(u == v) vc.pb(tot-2); else pre[u] = v; } scanf("%d", &q); for(int i = 1; i <= q; ++i) scanf("%d%d", &p[i].fi, &p[i].se); for(int x : vc){ ok[x] = 1; ok[x^1] = 1; memset(d, INF, sizeof(d)); Dij(to[x], 1); Dij(to[x^1], 0); for(int i = 1; i <= q; ++i){ ans[i] = min3(ans[i], d[p[i].fi][0]+d[p[i].se][1]+ct[x],d[p[i].fi][1]+d[p[i].se][0]+ct[x]); } ok[x] = 0; ok[x^1] = 0; } for(int x : vc) ok[x] = ok[x^1] = 1; dfs(0,1); for(int i = 1; i <= q; ++i) ans[i] = min(ans[i], dis(p[i].fi, p[i].se)); for(int i = 1; i <= q; ++i) printf("%lld\n", ans[i]); return 0; }
题意:问最小花费。
题解:线段树合并。
我们每次插入一个点之前,先判断一下这个点是不是已经加过数了,如果加过数了我们就把这个数先往后移动,移动到没有加过数的地方。
然后现在一定是一个没有加过数的位置了,然后我们用动态线段树维护信息,注意我们插入的位置是b的。
然后在当前位置前面的有没有出现过数,有就和前面的合并。
对于后面的一样处理。
然后在合并的过程中,我们明白后面大的数一定是要到左边去的。
所以在合并的时候就更新答案。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const int _inf = 0xc0c0c0c0; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL _INF = 0xc0c0c0c0c0c0c0c0; const LL mod = (int)1e9+7; const int N = 5e6; int n; struct Node{ int ls, rs, num; LL sum; Node(){ ls = rs = num = sum = 0; } }tr[N]; int tot; void Insert(int &p, int b, int l, int r){ if(p == 0) p = ++tot; if(l == r) { ++tr[p].num; tr[p].sum = b; return ; } int m = l+r >> 1; if(b <= m) Insert(tr[p].ls, b, l, m); else Insert(tr[p].rs, b, m+1, r); tr[p].sum = tr[ tr[p].ls ].sum + tr[ tr[p].rs ].sum; tr[p].num = tr[ tr[p].ls ].num + tr[ tr[p].rs ].num; } LL ans = 0; int Merge(int l, int r, int px, int py){ if(!px) return py; if(!py) return px; tr[px].num += tr[py].num; tr[px].sum += tr[py].sum; if(l != r){ int m = l+r >> 1; ans = ans - tr[tr[py].rs].sum * tr[tr[px].ls].num + tr[tr[px].ls].sum * tr[tr[py].rs].num; tr[px].ls = Merge(l, m, tr[px].ls, tr[py].ls); tr[px].rs = Merge(m+1, r, tr[px].rs, tr[py].rs); } return px; } int pre[N]; int r[N], rt[N]; int Find(int x){ if(x == pre[x]) return x; return pre[x] = Find(pre[x]); } int main(){ int n; scanf("%d", &n); for(int i = 1; i < N; ++i){ pre[i] = i; r[i] = i; } int a, b; for(int i = 1; i <= n; ++i){ scanf("%d%d", &a, &b); if(rt[a] != 0){ int p = Find(a); int rr = r[p] + 1; ans += 1ll * b * (rr-a); a = rr; Insert(rt[a], b, 1, n); if(rt[a-1] != 0){ int lx = Find(a-1); r[lx] = a; pre[a] = lx; rt[lx] = Merge(1,n,rt[lx],rt[a]); } if(rt[a+1] != 0){ int rx = Find(a+1); int lx = Find(a); r[lx] = r[rx]; pre[rx] = lx; rt[lx] = Merge(1,n,rt[lx],rt[rx]); } printf("%lld\n", ans); } return 0; }