2019 Multi-University Training Contest 1 题解

1001 - Blank

$dp$。给的限制条件是一些区间内出现的数字种类数,其实比较容易联想到一个经典的题,就是一个序列以及很多组询问,每个询问查询一个区间内不同种类的数字个数,这个题的一个做法是将询问按右端点升序排序,然后扫描线,用线段树维护每个数字出现的最晚位置。这个题由于数字种类本身很少,只有四种,所以我们可以用$dp[i][a][b][c][d]$来前$i$个位置,四种数字最近出现的位置分别是$a,b,c,d$的方案数,但是这样内存不够,其实有一维是可以省去的,因为$a,b,c,d$中恰有一个是$i$,然后其实我们不用关心具体是哪个数字出现在某个位置,因此,我们可以简化状态,用$dp[i][a][b][c]$表示前$i$个位置,除第$i$个位置的数字外,其他三种数字分别出现在$a,b,c$的方案数,其中$a\leq b \leq c$,转移比较显然,这里不赘述。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 const int mod=998244353;
 5 inline void upd(int &a,int x) {
 6     a+=x;
 7     if(a>=mod) a-=mod;
 8 }
 9 const int N=101;
10 int n,m,dp[2][N][N][N];
11 typedef std::pair<int,int> P;
12 std::vector<P> g[N];
13 int main() {
14     int T;
15     scanf("%d",&T);
16     while(T--) {
17         scanf("%d%d",&n,&m);
18         for(int i=1;i<=n;i++) g[i].clear();
19         for(int l,r,x;m--;) {
20             scanf("%d%d%d",&l,&r,&x);
21             g[r].push_back(P(l,x));
22         }
23         dp[1][0][0][0]=4;
24         int ans=0;
25         for(int i=1;i<=n;i++) {
26             int t=i&1;
27             if(i<n) for(int x=0;x<=i;++x) for(int y=x;y<=i;y++) for(int z=y;z<=i;z++) dp[t^1][x][y][z]=0;
28             for(int x=0;x<i;++x) for(int y=x;y<i;y++) for(int z=y;z<i;z++) if(dp[t][x][y][z]) {
29                 bool f=true;
30                 for(auto &c:g[i]) {
31                     int num=1;
32                     if(x>=c.first) num+=3;
33                     else if(y>=c.first) num+=2;
34                     else if(z>=c.first) num++;
35                     if(num!=c.second) {
36                         f=false;
37                         break;
38                     }
39                 }
40                 if(!f) {
41                     dp[t][x][y][z]=0;
42                     continue;
43                 }
44                 if(i==n) upd(ans,dp[t][x][y][z]);
45                 else {
46                     upd(dp[t^1][x][y][z],dp[t][x][y][z]);
47                     upd(dp[t^1][y][z][i],dp[t][x][y][z]);
48                     upd(dp[t^1][x][z][i],dp[t][x][y][z]);
49                     upd(dp[t^1][x][y][i],dp[t][x][y][z]);
50                 }
51             }
52         }
53         printf("%d\n",ans);
54     }
55     return 0;
56 }
View Code

1012 - Sequence

$NTT$。如果我们令$f=\sum_{i=1}^n a_ix^i$,$g(c)=\sum_{i=0}x^{ci}$,那么经过$m$次操作后,最终的序列的第$i$项,就是$f\prod_{i=1}^mg(c_i)$的$x^i$的系数。我们令$h=\prod_{i=1}^mg(c_i)$,由此可以看出,操作的顺序对结果是无影响的,由此,我们可以按$c_i$的值分类计算。首先我们考虑$c_i=1$的情况,这个时候有$g(1)=\sum_{i=0}x^i$,设$c_i=1$的操作有$k$个,那么显然有$g(1)^k=\sum_{i=0}C_{i+k-1}^{i}x^i$,因为这相当于是在计算将$i$个无区别的物品放入$k$个有区别的箱子中的方案数。对于$c_i=2$以及$c_i=3$的情况,其实计算是一样的,这里不赘述,最后我们用$NTT$加速乘法即可。

猜你喜欢

转载自www.cnblogs.com/Onlymyheart/p/11235285.html