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

 

posted @ 2019-07-28 21:10  UtopioSPH  阅读(146)  评论(0编辑  收藏  举报