2019 Multi-University Training Contest 1
A
Significance: Four colours are dyed for a sequence of length n, with m restrictions. There are exactly (x_i) colours in each shape ([l_i,r_i]) interval. Ask the number of legitimate plans. \ (n, mle 100)
key: dp
In fact, the idea is simple, the main problem is how to record the state to express this limitation. Consider how to express the number of colors in an interval: first, the interval must have been dyed, and secondly, each color contributes only 1. The latter can be represented by the location of the last occurrence of the color.
So (f {i, j, k, l}) denotes the location where the four colors last appear. In order to express convenience, they can be ordered: after the last occurrence of the four colors, the score ratio is \(i, j, k, l,\i < J < K < l). This allows you to check the validity of all intervals ending with L each time. Complexity(O(n^4+n^3m)
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef long double LD; typedef pair<int,int> pii; typedef pair<LL,int> pli; const int SZ = 8e6 + 10; const int INF = 1e9 + 10; const int mod = 998244353; const LD eps = 1e-8; LL read() { LL n = 0; char a = getchar(); bool flag = 0; while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); } while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); } if(flag) n = -n; return n; } int f[2][110][110][110]; vector<pii> q[110]; bool check(int i,int j,int k,int t) { for(pii p : q[t]) { int l = p.first,x = p.second; //cout << l << " " << x << endl; if(l<=i) if(x!=4) return false; else continue; if(l<=j) if(x!=3) return false; else continue; if(l<=k) if(x!=2) return false; else continue; if(l<=t) if(x!=1) return false; else continue; } return true; } int main() { int T = read(); while(T --) { int n = read(),m = read(); for(int i = 1;i <= n;i ++) q[i].clear(); for(int i = 1;i <= m;i ++) { int l = read(),r = read(),x = read(); q[r].push_back(make_pair(l,x)); } // cout << check(0,1,2,3) << endl; memset(f,0,sizeof f); f[0][0][0][0] = 1; for(int t = 0,cur = 0;t < n;t ++,cur^=1) { for(int k = 0;k <= max(t-1,0);k ++) for(int j = 0;j <= max(k-1,0);j ++) for(int i = 0;i <= max(j-1,0);i ++) f[cur^1][i][j][k] = 0; for(int k = 0;k <= max(t-1,0);k ++) { for(int j = 0;j <= max(k-1,0);j ++) { for(int i = 0;i <= max(j-1,0);i ++) { if(check(i,j,k,t)) { // printf("(%d,%d,%d,%d) = %d\n",i,j,k,t,f[cur][i][j][k]); (f[cur^1][j][k][t] += f[cur][i][j][k]) %= mod; (f[cur^1][i][k][t] += f[cur][i][j][k]) %= mod; (f[cur^1][i][j][t] += f[cur][i][j][k]) %= mod; (f[cur^1][i][j][k] += f[cur][i][j][k]) %= mod; } // else printf("!(%d,%d,%d,%d) = %d\n",i,j,k,t,f[cur][i][j][k]); } } } } int ans = 0; for(int k = 0;k <= max(n-1,0);k ++) { for(int j = 0;j <= max(k-1,0);j ++) { for(int i = 0;i <= max(j-1,0);i ++) { if(check(i,j,k,n)) { (ans += f[n&1][i][j][k]) %= mod; } } } } printf("%d\n",ans); } } /** 2 4 1 1 3 3 */
B
Topic: Give a sequence, each operation is to add a number at the end of the query interval within the linear basis. Mandatory online. \ (n, m le 2 * 10 ^ 5 )
key: linear basis
CF1100F
C
D
E
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef long double LD; typedef pair<int,int> pii; typedef pair<LL,int> pli; const int SZ = 8e6 + 10; const int INF = 1e9 + 10; const int mod = 998244353; const LD eps = 1e-8; LL read() { LL n = 0; char a = getchar(); bool flag = 0; while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); } while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); } if(flag) n = -n; return n; } vector<pii> g[SZ]; LL dist[SZ]; bool vis[SZ]; int n,m; void dij(int s) { for(int i = 1;i <= n;i ++) dist[i] = 1e18,vis[i] = 0; dist[s] = 0; priority_queue<pli> q; q.push(make_pair(0,s)); while(q.size()) { int u = q.top().second; q.pop(); if(vis[u]) continue; vis[u] = 1; for(pii e : g[u]) { int v = e.first; if(dist[v] > dist[u] + e.second) { dist[v] = dist[u] + e.second; q.push(make_pair(-dist[v],v)); } } } } struct edge { int f,t; LL d; }l[SZ]; int head[SZ],nxt[SZ],tot = 1; void build(int f,int t,LL d) { l[++ tot] = (edge){f,t,d}; nxt[tot] = head[f]; head[f] = tot; } void insert(int f,int t,LL d) { build(f,t,d); build(t,f,0); } int deep[SZ]; bool bfs(int s,int e) { for(int i = 1;i <= n;i ++) deep[i] = 0; deep[s] = 1; queue<int> q; q.push(s); while(q.size()) { int u = q.front(); q.pop(); for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(l[i].d && !deep[v]) { deep[v] = deep[u] + 1; q.push(v); if(v == e) return true; } } } return false; } LL dfs(int u,LL flow,int e) { if(u == e || flow == 0) return flow; LL ans = flow; for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(l[i].d && deep[v] == deep[u] + 1) { LL f = dfs(v,min(ans,l[i].d),e); if(f > 0) { l[i].d -= f; l[i^1].d += f; ans -= f; if(ans == 0) break; } else deep[v] = 0; } } if(ans == flow) deep[u] = 0; return flow - ans; } LL dinic(int s,int e) { LL ans = 0; while(bfs(s,e)) { LL tmp = dfs(s,1e18,e); if(tmp == 0) break; ans += tmp; } return ans; } int ff[SZ],tt[SZ],dd[SZ]; int main() { int T = read(); while(T --) { n = read(),m = read(); for(int i = 1;i <= n;i ++) g[i].clear(),head[i] = 0; tot = 1; for(int i = 1;i <= m;i ++) { int x = read(),y = read(),z = read(); g[x].push_back(make_pair(y,z)); ff[i] = x; tt[i] = y; dd[i] = z; } dij(1); if(dist[n] == 1e18) { puts("0"); continue; } for(int i = 1;i <= m;i ++) { if(dist[tt[i]] == dist[ff[i]] + dd[i]) { insert(ff[i],tt[i],dd[i]); } } printf("%lld\n",dinic(1,n)); } }
F
Title: Define string generation operations: add a character from the tail at the cost of p, or a substring of the current string from the tail at the cost of q. Ask the minimum cost of generating a given string. \ ( sum | S | Le 5 * 10 ^ 6 )
key: sam
Apparently for dp. It's easy to get a dp: add a character, or from a previous location. The latter must be a substring of the current string suffix that removes its string. Specifically, [j+1,i] is a substring of [1,j].
There may be many such js. As the cost increases with the increase of length, it must be the smallest maintenance j. Consider that a j has been maintained, and when a character is added, either it does not move or it walks on sam. So the complexity is(O(n)
G
H
I
Topic: Give a string exactly the length of k, and the number of occurrences of each character in ([l_i,r_i]) is the smallest subsequence of dictionary order. \ ( sum | S | le 3 * 10 ^ 5 )
key: Greed
There is no limit on the number of occurrences, that is, the previous question of garlic, which is more restrictive.
Considering that a prefix has been constructed and the current position is p, consider which character to choose next. It must be that after p, the dictionary order is as small as possible, and after selecting it, the answer that meets the requirement can be constructed.
Since the same letter must be selected as the most advanced position, there are at most O(m) positions to be selected, and a check is O(m). So the complexity is (O(nm 2), where m is the character set, that is 26.
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef long double LD; typedef pair<int,int> pii; typedef pair<LL,int> pli; const int SZ = 1e6 + 10; const int INF = 1e9 + 10; const int mod = 998244353; const LD eps = 1e-8; LL read() { LL n = 0; char a = getchar(); bool flag = 0; while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); } while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); } if(flag) n = -n; return n; } char a[SZ]; int k,n; char S[SZ]; int top; int b[SZ][27],L[27],R[27]; bool check(int a[27],int len,int b[27]) { int suml = 0,sumr = 0,sum = 0,s = 0; for(int i = 0;i < 26;i ++) { if(a[i] + b[i] < L[i]) return false; if(a[i] < L[i]) { sum += L[i] - a[i]; } if(a[i] > R[i]) return false; s += min(b[i],R[i]-a[i]); suml += L[i]; sumr += R[i]; } if(s < len) return false; if(!(suml <= k && k <= sumr)) return false; if(sum > len) return false; return true; } char ans[SZ]; int main() { while(~scanf("%s%d",a,&k)) { for(int i = 0;i < 26;i ++) L[i] = read(),R[i] = read(); int n = strlen(a); memset(b[n],0,sizeof b[n]); vector<int> g[27]; for(int i = 0;i < n;i ++) g[a[i]-'a'].push_back(i); for(int i = n-1;i >= 0;i --) { for(int j = 0;j < 26;j ++) b[i][j] = b[i+1][j]; b[i][a[i]-'a'] ++; } if(!check(b[n],k,b[0])) { puts("-1"); continue; } int nowid = -1; int h[27] = {},num[27] = {}; for(int len = 0;len < k;len ++) { for(int i = 0;i < 26;i ++) { while(h[i] < g[i].size() && g[i][h[i]] <= nowid) h[i] ++; if(h[i] == g[i].size()) continue; int tmp[27] = {},id = g[i][h[i]]; for(int j = 0;j < 26;j ++) tmp[j] = num[j]; tmp[i] ++; if(check(tmp,k-len-1,b[id+1])) { // printf("%d %d %d\n",len,i,id); nowid = id; ans[len] = i+'a'; num[i] ++; break; } } } for(int i = 0;i < k;i ++) printf("%c",ans[i]); puts(""); } }
J
K
Subject: Request
\[
\sum_{1\le i \le n} \gcd(\lfloor \sqrt[3]{i} \rfloor,i), \ n \le 10^{21}
\]
key: deduction
Mainly foolish, stuck in a strange place...
Enumerate the value after three root numbers, \( lfloor sqrt [3] {n} rfloor) Special judgment. It's easy to push.
\[
\sum_{d\le m-1} \phi(d) \sum_{i\le (m-1)/d} \lfloor\frac{(id+1)^3-1}{d}\rfloor - \lfloor\frac{(id)^3-1}{d}\rfloor
\]
And then the seemingly awkward thing in the back just unfolds... Then we get a (O(n^{1/3}))approach.
#include<bits/stdc++.h> using namespace std; typedef __int128 LL; typedef long double LD; typedef pair<int,int> pii; typedef pair<LL,int> pli; const int SZ = 1e7 + 10; const int INF = 1e9 + 10; const int mod = 998244353; const LD eps = 1e-8; template <class T> void read(T &x) { static char ch;static bool neg; for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar()); for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar()); x=neg?-x:x; } LL sqrt3(LL n) { LL l = 0,r = 1e7+10; while(r-l>1) { LL mid = (l+r) / 2; if(mid * mid * mid <= n) l = mid; else r = mid; } return l; } int phi[SZ]; LL sum[SZ]; int pri[SZ / 10]; bool vis[SZ]; void shai(int n) { phi[1] = 1; int tot = 0; for(int i = 2;i <= n;i ++) { if(!vis[i]) pri[++ tot] = i,phi[i] = i-1; for(int j = 1,m;j <= tot && (m=i*pri[j]) <= n;j ++) { vis[m] = 1; if(i%pri[j] == 0) { phi[m] = phi[i] * pri[j]; break; } else { phi[m] = phi[i] * phi[pri[j]]; } } } } LL ksm(LL a,LL b) { LL ans = 1; while(b) { if(b&1) ans = a * ans % mod; a = a *a % mod; b >>= 1; } return ans; } LL ni6 = ksm(6,mod-2); LL ni2 = ksm(2,mod-2); LL f2(LL n) { return n * (n+1) * (2*n+1) / 6; } LL f1(LL n) { return n * (n+1) / 2; } int baoli(int n) { int ans = 0; for(int i = 1;i <= n;i ++) { int x = (int)(pow(i,1.0/3)+1e-6); ans += __gcd(x,i); } return ans; } int main() { shai(1e7); int T; read(T); while(T --) { LL n; read(n); int m = sqrt3(n); // cout << m << endl; LL ans = 0; for(int d = 1;d < m;d ++) { LL tmp = 3*d*f2((m-1)/d)+ 3*f1((m-1)/d) + ((m-1)/d); ans += phi[d] * tmp; } // cout << ans << endl; for(int d = 1;d <= m;d ++) { if(m % d == 0) { ans += phi[d] * (((n/d) - ((LL)m*m*m-1)/d)); } } ans %= mod; cout << ans << endl; } }
L
Subject meaning: Give a sequence a, m operations, each time asking $b_i = sum {j = I - k cdot x} a_j bmod (0 Leq x, 1 Leq j Leq i) $, and then replace \\\\\\\\ with \\\ Find the final sequence. \ (n Le 10 ^ 5, m Le 10 ^ 6, k in {1, 2, 3})
key: ntt
It's very clear in the solution...
Firstly, the generating function is analyzed: ( sum b_i x^ i=( sum x ^ {ki}) ( sum a_ix ^ i)), so it satisfies the exchange law, and the order is irrelevant. The problem is to find ( sum x ^ {ki}) ^ n= sum {n-1+i select i} x ^{ki}. And then it's done.
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef long double LD; typedef pair<int,int> pii; typedef pair<LL,int> pli; const int SZ = 2e6 + 10; const int INF = 1e9 + 10; const int mod = 998244353; const LD eps = 1e-8; LL read() { LL n = 0; char a = getchar(); bool flag = 0; while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); } while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); } if(flag) n = -n; return n; } LL ksm(LL a,LL b) { LL ans = 1; while(b) { if(b&1) ans = a * ans % mod; a = a *a % mod; b >>= 1; } return ans; } struct NTTranform { const int g = 3; void Transform(int *a,int n,int opt) { for(int i = 0,j = 0;i < n;i ++) { if(i < j) swap(a[i],a[j]); for(int k = n >> 1;(j ^= k) < k;k >>= 1); } for(int l = 2;l <= n;l *= 2) { int m = l / 2; int wn = ksm(g,(mod-1)/l); if(opt == -1) wn = ksm(wn,mod - 2); for(int *p = a;p != a + n;p += l) { for(int i = 0,w = 1;i < m;i ++,w=1ll*w*wn%mod) { int t = 1ll * w * p[m + i] % mod; p[m + i] = (p[i] - t + mod) % mod; (p[i] += t) %= mod; } } } } void dft(int *a,const int n) { Transform(a,n,1); } void idft(int *a,const int n) { Transform(a,n,-1); int t = ksm(n,mod - 2); for(int i = 0;i < n;i ++) a[i] = 1ll * a[i] * t % mod; } }ntt; void multiply(int *a,int n,int *b,int m,int *ans) { /// need 4 times memory static int c1[SZ],c2[SZ]; int len = 1; while(len < n + m) len *= 2; for(int i = 0;i < len;i ++) c1[i] = c2[i] = 0; for(int i = 0;i < n;i ++) c1[i] = a[i]; for(int i = 0;i < m;i ++) c2[i] = b[i]; ntt.dft(c1,len); ntt.dft(c2,len); for(int i = 0;i < len;i ++) c1[i] = 1ll * c1[i] * c2[i] % mod; ntt.idft(c1,len); for(int i = 0;i < n + m - 1;i ++) ans[i] = (c1[i] + mod) % mod; } int a[SZ],b[SZ],c[SZ],fac[SZ],invfac[SZ]; int C(int n,int m) { if(n<m) return 0; return 1ll * fac[n] * invfac[m] % mod * invfac[n-m] % mod; } int main() { fac[0] = 1; for(int i = 1;i <= 2e6;i ++) fac[i] = 1ll * i * fac[i-1] % mod; for(int i = 0;i <= 2e6;i ++) invfac[i] = ksm(fac[i],mod-2); int T = read(); while(T --) { int n = read(),m = read(); for(int i = 0;i < n;i ++) a[i] = read(); int t[4] = {}; for(int i = 1;i <= m;i ++) t[read()] ++; for(int k = 1;k <= 3;k ++) { if(t[k] == 0) continue; for(int i = 0;i < n;i ++) b[i] = c[i] = 0; b[0] = 1; int m = t[k]; for(int i = 0;i < n;i += k) c[i] = C(i/k-1+m,i/k); // for(int i = 0;i < n;i ++) printf("%d ",b[i]); puts(""); // for(int i = 0;i < n;i ++) printf("%d ",c[i]); puts(""); multiply(b,n,c,n,b); // for(int i = 0;i < n;i ++) printf("%d ",b[i]); puts(""); multiply(b,n,a,n,a); } LL ans = 0; // for(int i = 0;i < n;i ++) printf("%d ",a[i]); puts(""); for(int i = 0;i < n;i ++) { ans ^= (i+1ll) * a[i]; } printf("%lld\n",ans); } } /** 2 5 2 3 2 2 4 1 2 2 */
M
Question: Give two kinds of points on the two-dimensional plane, and ask if there is a straight line separating the two kinds of points. \ (nle 100)
key: computational geometry
Determine whether the two convex hulls are separated.