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 
View Code

 

 

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 
View Code

 

 

 

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 
View Code

 

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 
View Code

 

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 
View Code

 

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 
View Code

 

以上是关于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

2019 Multi-University Training Contest 2

2019 Multi-University Training Contest 2