NOIP2021总结

对于NOIP2021的全面总结

赛时:

考场拿到题目较为镇定,直接开 T1 ,一眼秒掉了根号预处理,$30min$ 喜提 $70pts$ 的好成绩。按照先暴力再正解的策略,去看 T2。读题后有些恍惚,没有看数据范围直接做,觉得不太可做,看了数据范围有 $m\leq 12$,果断计数 DP,转移后谨慎的判了边界条件,过掉了 7 位数样例后觉得 $50pts$ 稳了,哇,第一次考场上 dp 耶。T3 本来看上去非常亲切,之前模拟有两道无上限操作的题目,还有方差公式,设计了 dp 状态,但是并不会转移方差,想了很久无奈去写了暴搜。T4 题面很长,由于 T3 耽误了太多时间,T4暴力没有太敢写,因为一写又要很长时间,然后怕自己调不完,于是决定先去写 T1 正解。发现可以用类似埃氏筛法做,但怕复杂度炸掉,亲测规模 $2.8\times 10^7$,但考场上把八位数看成了八次方,所以以为自己被卡常了,觉得不太好,一直在想怎么改成类似于线性筛,于是时间流逝而去,T4暴力终究没写无奈固输,导致貌似有 $44pts$ 没拿到,非常可惜。

题目分析

T1

$70pts$ 根号维护,复杂度 $O(\sqrt n+T)$。正解类埃氏筛法,复杂度 $O(nloglogn)$ ?。

NOIP2021总结
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int vis[10000005],pos,ans[10000005],T,n[200005],maxn;
 4 bool check(int x)
 5 {
 6     while(x)
 7     {
 8         if(x % 10 == 7) return true;
 9         x /= 10;
10     }
11     return false;
12 }
13 int main()
14 {
15     freopen("number.in","r",stdin);
16     freopen("number.out","w",stdout);
17     scanf("%d",&T);
18     for(int t = 1;t <= T;t++)
19     {
20         scanf("%d",&n[t]);
21         maxn = max(n[t],maxn);
22     }
23     if(maxn <= 200000)
24     {
25         for(int i = 1;i <= 9;i++) vis[i] = (i == 7) ? -1 : 1;
26         for(int i = 10;i <= 200002;i++)
27         {
28             if(check(i)) 
29             {
30                 vis[i] = -1;
31                 continue;
32             }
33             int flag = 0;
34             for(int j = 1;j * j <= i;j++)
35             {
36                 if(i % j != 0) continue;
37                 if(vis[j] == -1 or vis[i / j] == -1) 
38                 {
39                     flag = 1;
40                     break;
41                 }
42             }
43             vis[i] = flag ? -1 : 1;
44         }
45         ans[200000] = 200002;
46         pos = 200000;
47         for(int i = 199999;i >= 1;i--)
48         {
49             if(vis[i] == -1) ans[i] = -1;
50             else
51             {
52                 ans[i] = pos;
53                 pos = i;
54             }
55         }
56         for(int t = 1;t <= T;t++)
57             printf("%d\n",ans[n[t]]);
58         return 0;
59     }
60     for(int i = 1;i <= 10000001;i++)
61     {
62         if(vis[i] == -1) continue;
63         if(not check(i)) continue;
64         for(int j = 1;j * i <= 10000001;j++)
65         {
66             if(vis[i*j] == -1) continue;
67             vis[i*j] = -1;
68         }
69     }
70     pos = 10000001;
71     for(int i = 10000000;i >= 1;i--)
72     {
73         if(vis[i] == -1) ans[i] = -1;
74         else
75         {
76             ans[i] = pos;
77             pos = i;
78         }
79     }
80     for(int t = 1;t <= T;t++)
81         printf("%d\n",ans[n[t]]);
82     return 0;
83 }
View Code

 

T2

$50pts$ 设 $f_{i,j}$ 表示第 $i$ 个填完后 $S$ 值为 $j$ 的权值和,计数转移即可,复杂度 $O(n^2m2^m)$。

NOIP2021总结
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 35;
 5 const ll mod = 998244353;
 6 ll f[N][150000];
 7 ll ans;
 8 ll v[110];
 9 int n,m,k;
10 bool check(int x)
11 {
12     int cnt = 0;
13     while(x)
14     {
15         if(x & 1) cnt++;
16         x >>= 1;
17     }
18     if(cnt > k) return false;
19     else return true;
20 }
21 int main()
22 {
23     freopen("sequence.in","r",stdin);
24     freopen("sequence.out","w",stdout);
25     scanf("%d%d%d",&n,&m,&k);
26     for(int i = 0;i <= m;i++) scanf("%lld",&v[i]);
27     for(int i = 0;i <= n * (1 << m);i++) f[0][i] = 1;
28     for(int i = 1;i <= n;i++)
29         for(int j = 0;j <= i * (1 << m);j++)
30             for(int k = 0;k <= m;k++)
31                 if(j - (1 << k) >= 0 and j - (1 << k) <= (i - 1) * (1 << m)) f[i][j] = (f[i][j] + f[i-1][j - (1 << k)] * v[k] % mod) % mod;
32     for(int i = n;i <= n * (1 << m);i++)
33     {
34         if(not check(i)) continue;
35         //cout << i << endl;
36         ans = (ans + f[n][i]) % mod;
37     }
38     printf("%lld\n",ans);
39     return 0;
40 }
View Code

 

T3

搜的性质没有找好,$12pts$,别人 $20pts$。(好像挂了?)

T4

。。。,时间与暴力,我。。。,没有看出特殊性质暴力分好拿非常可惜。

赛后

期望:$100+50+12+0=162$

实际:待测

上一篇:NOIP2021 打铁记(未写完,待更)


下一篇:【比赛游记】NOIP2021 游记