2019 Multi-University Training Contest 1 (补题)
Posted utopiosph001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019 Multi-University Training Contest 1 (补题)相关的知识,希望对你有一定的参考价值。
1001.Blank
题意:给一列数组填四种数,使得每个给定第$i$个的区间数的种类刚好有$x_i$种
我的思路:dp,状态排完序后是四种数最后的位置,转移时判断合法性即可(卡常有点厉害)
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 1e2 + 5; 5 const int MOD = 998244353; 6 7 int dp[2][N][N][N]; 8 int a[N][10]; 9 10 bool check(int i, int j, int k, int l) 11 12 13 return (a[l][1] == -1 || a[l][1] > k) && 14 (a[l][3] == -1 || (a[l][3] > j && a[l][4] <= k)) && 15 (a[l][5] == -1 || (a[l][5] > i && a[l][6] <= j)) && 16 (a[l][7] == -1 || a[l][8] <= i); 17 18 19 void fadd(int& a, int b) 20 21 a += b; 22 if (a >= MOD) a -= MOD; 23 24 25 int main() 26 27 int T; 28 scanf("%d", &T); 29 while (T --) 30 int n, m; 31 memset(a, -1, sizeof(a)); 32 scanf("%d%d", &n, &m); 33 for (int i = 0; i <= n; ++ i) 34 for (int j = 0; j <= n; ++ j) 35 for (int k = 0; k <= n; ++ k) 36 dp[0][i][j][k] = dp[1][i][j][k] = 0; 37 38 39 40 for (int i = 0; i < m; ++ i) 41 int l, r, k; 42 scanf("%d%d%d", &l, &r, &k); 43 a[r][k * 2] = max(a[r][k * 2], l); 44 if (a[r][k*2-1] == -1 || l<a[r][k*2-1]) 45 a[r][k*2-1] = l; 46 47 48 dp[0][0][0][0] = 1; 49 int pre = 0; 50 for (int l = 0; l < n; ++ l) 51 pre ^= 1; 52 for (int i = 0; i <= l + 2; ++ i) 53 for (int j = i; j <= l + 2; ++ j) 54 for (int k = j; k <= l + 2; ++ k) 55 dp[pre][i][j][k] = 0; 56 57 58 59 for (int i = 0; i <= l; ++ i) 60 for (int j = i; j <= l; ++ j) 61 for (int k = j; k <= l; ++ k) 62 fadd(dp[pre][i][j][k], dp[pre^1][i][j][k]); 63 fadd(dp[pre][i][j][l], dp[pre^1][i][j][k]); 64 fadd(dp[pre][i][k][l], dp[pre^1][i][j][k]); 65 fadd(dp[pre][j][k][l], dp[pre^1][i][j][k]); 66 67 68 69 for (int i = 0; i <= l; ++ i) 70 for (int j = i; j <= l; ++ j) 71 for (int k = j; k <= l; ++ k) 72 if (!check(i, j, k, l + 1)) dp[pre][i][j][k] = 0; 73 74 75 76 77 int ans = 0; 78 for (int i = 0; i < n; ++ i) 79 for (int j = i; j < n; ++ j) 80 for (int k = j; k < n; ++ k) 81 fadd(ans, dp[pre][i][j][k]); 82 83 84 85 printf("%d\n", ans); 86 87 return 0; 88
1002.Operation
题意:给定一个数列,执行两种操作,第一种是询问区间选数异或能取到的最大值,第二种是在数组尾巴上添加一个数
思路:贪心+线性基,从左往右维护n个线性基,更新线性基时贪心地维护高位最近更新坐标,询问时从高位往低位贪,对于询问$l$,$r$,如果$r$位线性基高位最近更新坐标不小于$l$,我们便可尝试异或该位上的数。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 1e6 + 5; 5 6 int ind[N][31], f[N][31]; 7 8 void Insert(int x, int p) 9 10 int np = p; 11 for (int i = 30; i >= 0; -- i) 12 f[p][i] = f[p - 1][i]; 13 ind[p][i] = ind[p - 1][i]; 14 15 for (int i = 30; i >= 0; -- i) 16 if ((x >> i) & 1) 17 if (!ind[p][i]) 18 ind[p][i] = np; f[p][i] = x; 19 break; 20 21 if (ind[p][i] < np) 22 swap(ind[p][i], np); 23 swap(f[p][i], x); 24 25 x ^= f[p][i]; 26 27 28 29 30 int main() 31 32 int T; 33 scanf("%d", &T); 34 while (T --) 35 int n, m; 36 scanf("%d%d", &n, &m); 37 for (int i = 1; i <= n; ++ i) 38 int x; 39 scanf("%d", &x); 40 Insert(x, i); 41 42 int ans = 0; 43 for (int i = 0; i < m; ++ i) 44 int cmd; 45 scanf("%d", &cmd); 46 if (cmd == 0) 47 int l, r; 48 scanf("%d%d", &l, &r); 49 l ^= ans; l = l % n + 1; 50 r ^= ans; r = r % n + 1; 51 if (l > r) swap(l, r); 52 ans = 0; 53 for (int j = 30; j >= 0; -- j) 54 if (ind[r][j] >= l && (ans ^ f[r][j]) > ans) 55 ans ^= f[r][j]; 56 57 58 printf("%d\n", ans); 59 else 60 int x; 61 scanf("%d", &x); 62 x ^= ans; 63 Insert(x, n + 1); 64 n ++; 65 66 67 68 return 0; 69
1004.Vacation
题意:给出一堆车地长度,坐标和速度,问tom的车到达斑马线的时间是多少。
我的思路:算出每辆车到达不会于阻挡tom车(到达斑马线)的位置,取最大值。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 1e5 + 5; 5 6 double l[N], s[N], v[N]; 7 8 int main() 9 10 int n; 11 while (scanf("%d", &n) != EOF) 12 for (int i = 0; i <= n; ++ i) 13 scanf("%lf", l + i); 14 if (i > 1) l[i] += l[i - 1]; 15 16 for (int i = 0; i <= n; ++ i) 17 scanf("%lf", s + i); 18 if (i > 0) s[i] += l[i]; 19 20 double t = 0; 21 for (int i = 0; i <= n; ++ i) 22 scanf("%lf", v + i); 23 t = max(t, s[i] / v[i]); 24 25 printf("%.10f\n", t); 26 27 return 0; 28
1009.String
题意:给定一个串,取一个固定长子序列使得每个字母恰好出现$(L_i, R_i)$次
我的思路:枚举子序列第i位,贪心放字母并判断该操作是否合法。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 1e5 + 5; 5 6 char s[N], ans[N]; 7 int lft[N][26]; 8 int num[26]; 9 int L[26], R[26]; 10 int k; 11 12 int main() 13 14 while (scanf("%s%d", s, &k) != EOF) 15 int l = strlen(s); 16 memset(lft[l], 0, sizeof(lft[l])); 17 memset(num, 0, sizeof(num)); 18 for (int i = l - 1; i >= 0; -- i) 19 for (int j = 0; j < 26; ++ j) 20 lft[i][j] = lft[i + 1][j]; 21 22 lft[i][s[i] - ‘a‘] ++; 23 24 int sr = 0, sl = 0; 25 for (int i = 0; i < 26; ++ i) 26 scanf("%d%d", L + i, R + i); 27 sr += R[i]; 28 sl += L[i]; 29 30 if (sr < k || sl > k) 31 puts("-1"); 32 continue; 33 34 vector<int> a[26]; 35 int pos[26] = 0; 36 for (int i = 0; i < l; ++ i) 37 a[s[i] - ‘a‘].emplace_back(i); 38 39 int ptr = -1, sum = 0; 40 for (int i = 0; i < k; ++ i) 41 for (int j = 0; j < 26; ++ j) 42 while (pos[j] < (int)a[j].size() && a[j][pos[j]] <= ptr) 43 pos[j] ++; 44 45 if (pos[j] == (int)a[j].size()) continue; 46 int ps = a[j][pos[j]]; 47 if (num[j] + 1 > R[j]) continue; 48 if (sl + sum + (num[j] >= L[j]) > k) continue; 49 num[j] ++; 50 int ok = 1, st = 0; 51 for (int t = 0; t < 26; ++ t) 52 if (num[t] + lft[ps + 1][t] < L[t]) 53 ok = 0; break; 54 55 st += num[t] + min(R[t] - num[t], lft[ps + 1][t]); 56 57 if (!ok || st < k) 58 num[j] --; continue; 59 60 ptr = a[j][pos[j]]; 61 sum ++; sl -= (num[j] <= L[j]); 62 ans[i] = j + ‘a‘; 63 break; 64 65 66 ans[k] = ‘\0‘; 67 printf("%s\n", ans); 68 69 return 0; 70
1011.Function
题意:给定n,求
$$\sum_i=1^n\gcd(\lfloor\sqrt[3]i\rfloor,i)\mod 998244353$$
我的思路:反过来枚举开立方后的数,利用狄利克雷卷积相关的公式化简表达式(由于时间原因推导暂时不写上来了,以后再补上,Tex写起来很麻烦滴),卡常卡到欲仙欲死。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef __int128 ll; 5 6 const int MOD = 998244353; 7 const int N = 1e7 + 5; 8 9 int cnt = 0; 10 int prime[N / 10]; 11 int phi[N]; 12 bool vis[N]; 13 14 namespace fastIO 15 //fread -> read 16 const int BUF_SIZE = 1000000; 17 bool IOerror = 0; 18 inline char nc() 19 //FILE* fp=fopen("123.txt","r"); 20 static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE; 21 if(p1 == pend) 22 p1 = buf; 23 pend = buf + fread(buf, 1, BUF_SIZE, stdin); 24 if(pend == p1) 25 IOerror = 1; 26 return -1; 27 28 29 return *p1++; 30 31 32 //输入挂,EOF返回0,有输入返回1. 33 template <class T> 34 inline bool read(T &ret) 35 char c; 36 if (c = nc(), c == EOF)return 0; //EOF 37 while(c != ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = nc(); 38 int sgn = (c == ‘-‘) ? -1 : 1; 39 ret = (c == ‘-‘) ? 0 : (c - ‘0‘); 40 while(c = nc(), c >= ‘0‘ && c <= ‘9‘) ret = ret*10 + (c-‘0‘); 41 ret *= sgn; 42 return 1; 43 44 template <class T> 45 inline void print(T x) 46 if(x>9) print(x/10); 47 putchar(x%10+‘0‘); 48 49 ; using fastIO::read; using fastIO::print; 50 51 void init() 52 53 phi[1] = 1; 54 for (int i = 2; i < N; ++ i) 55 if (!vis[i]) 56 prime[cnt ++] = i; 57 phi[i] = i - 1; 58 59 for (int j = 0; j < cnt && prime[j] * i < N; ++ j) 60 vis[prime[j] * i] = 1; 61 if (i % prime[j] == 0) 62 phi[prime[j] * i] = phi[i] * prime[j]; 63 break; 64 else 65 phi[prime[j] * i] = phi[i] * (prime[j] - 1); 66 67 68 69 70 71 void fadd(int& a, ll b) 72 73 a += b; 74 if (a >= MOD) a -= MOD; 75 76 77 void fsub(int& a, ll b) 78 79 a -= b; 80 if (a < 0) a += MOD; 81 82 83 ll solve(ll r, ll n) 84 85 if (r * r * r > n) return 0; 86 ll l = r * r * r - 1; 87 int rtn = 0; 88 int tmp = r; 89 int sqt = sqrt(tmp); 90 for (int i = 1; i <= sqt; ++ i) 91 if (r % i == 0) 92 fadd(rtn, ((n / i) - (l / i)) * phi[i] % MOD); 93 if (i * i != r) 94 fadd(rtn, ((n / (r / i)) - (l / (r / i))) * phi[r / i] % MOD); 95 96 97 98 return rtn; 99 100 101 int main() 102 103 init(); 104 int T; 105 read(T); 106 while (T --) 107 ll n; 108 read(n); 109 if (n <= 10) 110 int ans = 0; 111 for (int i = 1; i <= n; ++ i) 112 ans += __gcd((int)sqrt(i), i); 113 114 printf("%d\n", ans); 115 continue; 116 117 int R; 118 for (int i = 1; ; ++ i) 119 ll k = i; k = k * k * k; 120 if (k - 1 > n) break; 121 R = i - 1; 122 123 int ans = 0; 124 for (int i = 1; i <= R; ++ i) 125 int d = R / i; 126 int tmp = d + 3ll * d * (d + 1) / 2 % MOD; 127 tmp %= MOD; 128 fadd(tmp, 1ll * d * (d + 1) / 2 % MOD * (d * 2 + 1) % MOD * i % MOD); 129 tmp = 1ll * tmp * phi[i] % MOD; 130 ans += tmp; 131 if (ans >= MOD) ans -= MOD; 132 133 fadd(ans, solve(R + 1, n)); 134 printf("%d\n", ans); 135 136 return 0; 137
1012.Sequence
题意:给n长数列和m个操作(最多三种操作),每个操作给定一个k,执行$b_i = \sum_j = i - k \cdot x a_j (0 \leq x, 1\leq j \leq i)$并替换$a_i$,求m次操作后数列的值。
我的思路:根据没种操作的操作数我们可以算出其相应母函数$i$次系数,再用$ntt$进行至多三次卷积加速即可。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 namespace fastIO 5 //fread -> read 6 const int BUF_SIZE = 1000000; 7 bool IOerror = 0; 8 inline char nc() 9 //FILE* fp=fopen("123.txt","r"); 10 static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE; 11 if(p1 == pend) 12 p1 = buf; 13 pend = buf + fread(buf, 1, BUF_SIZE, stdin); 14 if(pend == p1) 15 IOerror = 1; 16 return -1; 17 18 19 return *p1++; 20 21 22 //输入挂,EOF返回0,有输入返回1. 23 template <class T> 24 inline bool read(T &ret) 25 char c; 26 if (c=nc(),c==EOF)return 0; //EOF 27 while(c!=‘-‘&&(c<‘0‘||c>‘9‘))c=nc(); 28 int sgn =(c==‘-‘)?-1:1; 29 ret=(c==‘-‘)?0:(c - ‘0‘); 30 while(c=nc(),c>=‘0‘&&c<=‘9‘) ret=ret*10+(c-‘0‘); 31 ret *= sgn; 32 return 1; 33 34 template <class T> 35 inline void print(T x) 36 if(x>9) print(x/10); 37 putchar(x%10+‘0‘); 38 39 ; using fastIO::read; 40 41 const int N = 1e5 + 5; 42 const int M = 2e6 + 5; 43 const int MOD = 998244353; 44 45 typedef long long ll; 46 47 int A[N]; 48 int fac[M], inv[M]; 49 50 void init() 51 52 fac[0] = inv[0] = fac[1] = inv[1] = 1; 53 for (int i = 2; i < M; ++ i) 54 fac[i] = 1ll * fac[i - 1] * i % MOD; 55 inv[i] = 1ll * (MOD - MOD/i) * inv[MOD%i] % MOD; 56 57 for (int i = 2; i < M; ++ i) 58 inv[i] = 1ll * inv[i - 1] * inv[i] % MOD; 59 60 61 62 int fpow(int a, int b) 63 64 int rtn = 1; 65 while (b) 66 if (b & 1) rtn = 1ll * rtn * a % MOD; 67 a = 1ll * a * a % MOD; 68 b >>= 1; 69 70 return rtn; 71 72 73 inline int fadd(int a, int b) 74 75 a += b; 76 if (a >= MOD) a -= MOD; 77 return a; 78 79 80 inline int fsub(int a, int b) 81 82 a -= b; 83 if (a < 0) a += MOD; 84 return a; 85 86 87 int a[4 * N], b[4 * N]; 88 struct NTT 89 90 int siz; 91 void init(int n) 92 siz = 1; 93 for (; siz < (n << 1); siz <<= 1); 94 for (int i = 0; i < siz; ++ i) 95 a[i] = b[i] = 0; 96 97 98 void ntt(int *p, int f) 99 for (int i = 0, j = 0; i < siz; ++ i) 100 if (i < j) swap(p[i], p[j]); 101 for (int k = siz>>1; (j ^= k) < k; k >>= 1); 102 103 for(int i = 2; i <= siz; i <<= 1) 104 int nw = fpow(3, (MOD - 1) / i); 105 if (f == -1) 106 nw = fpow(nw, MOD - 2); 107 108 for (int j = 0, m = i >> 1; j < siz; j += i) 109 for (int k = 0, w = 1; k < m; ++ k) 110 int t = 1ll * p[j + k + m] * w % MOD; 111 p[j + k + m] = fsub(p[j + k], t); 112 p[j + k] = fadd(p[j + k], t); 113 w = 1ll * w * nw % MOD; 114 115 116 117 if (f == -1) 118 int inv = fpow(siz, MOD - 2); 119 for (int i = 0; i < siz; ++ i) 120 p[i] = 1ll * p[i] * inv % MOD; 121 122 123 124 void fmul() 125 ntt(a, 1); ntt(b, 1); 126 for (int i = 0; i < siz; ++ i) 127 a[i] = 1ll * a[i] * b[i] % MOD; 128 129 ntt(a, -1); 130 131 ; 132 133 int C(int a, int b) 134 135 return 1ll * fac[a] * inv[b] % MOD * inv[a - b] % MOD; 136 137 138 int main() 139 140 init(); 141 int T; 142 read(T); 143 while (T --) 144 int n, m; 145 read(n); read(m); 146 for (int i = 0; i < n; ++ i) 147 read(A[i]); 148 149 int num[4] = 0; 150 for (int i = 0; i < m; ++ i) 151 int x; read(x); 152 num[x] ++; 153 154 NTT Nt; 155 Nt.init(n); 156 for (int i = 0; i < n; ++ i) 157 a[i] = A[i]; 158 159 for (int i = 1; i <= 3; ++ i) 160 if (num[i] == 0) continue; 161 for (int j = n; j < Nt.siz; ++ j) 162 a[j] = b[j] = 0; 163 164 for (int j = 0; j < n; ++ j) 165 b[j] = (j % i == 0 ? C(j / i + num[i] - 1, num[i] - 1) : 0); 166 167 Nt.fmul(); 168 169 ll ans = 0; 170 for (int i = 0; i < n; ++ i) 171 ans ^= 1ll * (i + 1) * a[i]; 172 173 printf("%lld\n", ans); 174 175 return 0; 176
以上是关于2019 Multi-University Training Contest 1 (补题)的主要内容,如果未能解决你的问题,请参考以下文章
2019 Multi-University Training Contest 6
2019 Multi-University Training Contest 6
2019 Multi-University Training Contest 6
2019 Multi-University Training Contest 3