abc359(atcoder beginer 359) C、D、E、F

 

C

这类小模拟题

1. 结果处理分类。可以用swap、函数等方法,简化类别

2. 不同的写法有可能是对称的

3. 这次用vscode,感觉chatgpt的自动补全很好,的确能理解我前面代码的意思,补全我当前代码可能的内容

4. 多造样例,有规律的

atcoder beginer基本上都有这样一道题

 

D

我比赛上的方法:

 

 dp+细节题

f[i][j] = sum{f[i-1][l]}

i:第i位

j:该位及前面k位

f[i][j]:可用数目

l:所有满足的情况

不用记录当前这位的情况

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define LL long long
  4 #define ULL unsigned long long
  5 
  6 const LL mod_2=998244353;
  7 
  8 const double eps_1=1e-5;
  9 const double eps_2=1e-10;
 10 
 11 const int maxn=1e3+10;
 12 const int maxe=1024+10;
 13 const int maxlen=12;
 14 
 15 int len,er[maxlen],q[maxlen];
 16 int pos[maxe][maxlen],pal[maxe];
 17 LL f[maxn][maxe],result=0;
 18 string str;
 19 
 20 void cal_value(int x)
 21 {
 22     int i,j,cnt_q=0,value=0,value_new,last_value,last_ch,pre_ch;
 23     for (i=x-len+1;i<=x;i++)
 24     {
 25         if (str[i]=='B')
 26             value += er[i - (x-len+1)];
 27         else if (str[i]=='?')
 28             q[cnt_q++] = i - (x-len+1);
 29     }
 30 
 31     for (i=0;i<er[cnt_q];i++)
 32     {
 33         value_new = value;
 34         for (j=0;j<cnt_q;j++)
 35             value_new += er[ q[j] ] * pos[i][j];
 36         if (!pal[value_new])
 37         {
 38             if (str[x]!='?')
 39                 last_ch = str[x]-'A';
 40             else
 41                 last_ch = pos[i][cnt_q-1];
 42             
 43             if (x==len-1)
 44                 f[x][value_new] = (f[x][value_new] + 1) % mod_2;
 45             else
 46             {
 47                 if (str[x-len]!='?')
 48                 {
 49                     pre_ch = str[x-len]-'A';
 50                     last_value = (value_new - last_ch * er[len-1]) * 2 + pre_ch;
 51                     if (!pal[last_value])
 52                         f[x][value_new] =(f[x][value_new] + f[x-1][last_value]) % mod_2;
 53                 }
 54                 else
 55                 {
 56                     for (pre_ch=0;pre_ch<2;pre_ch++)
 57                     {
 58                         last_value = (value_new - last_ch * er[len-1]) * 2 + pre_ch;
 59                         if (!pal[last_value])
 60                             f[x][value_new] =(f[x][value_new] + f[x-1][last_value]) % mod_2;
 61                     }
 62                 }
 63             }
 64         }
 65     }
 66 
 67 }
 68 
 69 int main()
 70 {
 71     int n,i,j,v;
 72     cin>>n>>len>>str;
 73 
 74     for (i=0;i<=len;i++)
 75         er[i] = 1<<i;
 76     memset(pal,0,sizeof(pal));
 77     for (i=0;i<er[len];i++)
 78     {
 79         v = i;
 80         for (j=0;j<len;j++)
 81         {
 82             pos[i][j] = v & 1;
 83             v>>=1;
 84         }
 85 
 86         for (j=0;j<len/2;j++)
 87             if (pos[i][j]!=pos[i][len-j-1])
 88                 break;
 89         if (j==len/2)
 90             pal[i] = 1;
 91     }
 92 
 93     memset(f,0,sizeof(f));
 94     for (i=len-1;i<n;i++)
 95         cal_value(i);
 96 
 97     for (i=0;i<er[len];i++)
 98         result = (result + f[n-1][i]) % mod_2;
 99     cout<<result;
100 
101     return 0;
102 }

 

我觉得这个代码写得比较长,找一下别人的代码,看怎么写这个000、001、010、011、100、…… 比较方便快捷 

 

chatgpt也是这样写

 

遍历从0到2^k,看当前串(当前这位是最靠右的位置)是否满足条件,这样感觉好写一点

感觉好写不少

j是前k位

l是当前位

 

j=0 to 1<<k 这样的写法,真的很爽。这样就不用一一找出所有的可能。如果当前写法不满足条件,前面dp[j]的值已经判断过了,肯定为0

l=0t o 2 这样的写法,真的很爽。这样就不用判断所有的情况,只用 if xxx continue就行

 

当DP能经常抱着这样的念头写的时候,就到了一定境界,代码数会少很多

 

还有比如只判断一半,没必要,全部判断好写

1         for (j=0;j<k;j++)
2             if (((i>>j)&1) != ((i>>(k-j-1))&1))
3                 ok=0;

 

 Submission #54807940 - UNIQUE VISION Programming Contest 2024 Summer (AtCoder Beginner Contest 359)

 

自己复写一下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define ULL unsigned long long
 5 
 6 const LL mod_2=998244353;
 7 
 8 const double eps_1=1e-5;
 9 const double eps_2=1e-10;
10 
11 const int maxn=1e3+10;
12 const int maxe=1024+10;
13 
14 LL dp[maxn][maxe],result=0;
15 bool pal[maxe];
16 
17 int main()
18 {
19     LL n,k,i,j,l,ok,new_i;
20     string str;
21     cin>>n>>k>>str;
22 
23     for (i=0;i<(1<<k);i++)
24     {
25         ok=1;
26         for (j=0;j<k;j++)
27             if (((i>>j)&1) != ((i>>(k-j-1))&1))
28                 ok=0;
29         pal[i] = ok ^ 1;
30     }
31 
32     memset(dp,0,sizeof(dp));
33     for (i=0;i<(1<<k);i++)
34     {
35         ok=1;
36         for (j=0;j<k;j++)
37         {
38             if (str[j]=='A' && ((i>>j)&1) == 1)
39                 ok=0;
40             if (str[j]=='B' && ((i>>j)&1) == 0)
41                 ok=0;
42         }
43         dp[k-1][i]=ok * pal[i];
44 
45     }
46 
47     for (j=k;j<n;j++)
48         for (l=0;l<2;l++)
49         {
50             if (str[j]=='A' && l==1)
51                 continue;
52 
53             if (str[j]=='B' && l==0)
54                 continue;
55 
56             for (i=0;i<(1<<k);i++)
57             {
58                 new_i = i/2+(1<<(k-1))*l;
59                 if (pal[new_i])
60                     (dp[j][new_i] += dp[j-1][i]) %= mod_2;
61             }
62                 
63         }
64 
65     for (i=0;i<(1<<k);i++)
66         (result += dp[n-1][i]) %= mod_2;
67     cout<<result;
68     return 0;
69 }

 

看前面几个人的代码,很短,不想看了…… emmm,就,找看得舒服的看就好,有大把选择

 

看题解,python代码很短

 是否回文数:

 

那c++的string也能一行解决

 

 

 不错不错

 

这个是当前向左所有长度为k的字符情况 -> 下一个字符向左所有长度为k的字符情况

这句话写得妙

 

tmp和mp就是起到,dp降维的作用而已

 

 这个是为了起到一开始不用预处理的作用。c++也可以在字符串前面添加,CC...C(k-1个C这样的操作),因为它无法构成回文数

 

字典序表的操作,学会了。这个代码的一些指令,多看多学多写,平时自己用python不熟,这个是很好的模板

 1 N, K = map(int, input().split())
 2 
 3 S = input()
 4 
 5 # Initially, fill with characters that are not A nor B
 6 mp = {'C' * (K - 1) : 1}
 7 
 8 for c in S:
 9     # Add one character to the tail
10     # Merge the cases for adding 'A' and adding 'B'
11     # If both addition is impossible, merge an empty dictionary
12     tmp = ({s + 'A' : v for s, v in mp.items()} if c != 'B' else {}) | ({s + 'B' : v for s, v in mp.items()} if c != 'A' else {})
13     
14     mp = {} # Erase the DP table
15     
16     for s, v in tmp.items():
17         if s != s[::-1]: # If it is not a palindrome, drop the first character and add it
18             if s[1:] in mp:
19                 mp[s[1:]] += v
20             else:
21                 mp[s[1:]] = v
22 
23 # The sum modulo 998244353 is the answer
24 print(sum(mp.values()) % 998244353)

 

 

 

 

E

题意很好懂,这类题,图文并茂。

当前位置i从右到左,找到第一个比它高的数(位置为j),结果(r[i])等于r[j]+h[i]*(i-j),如果没有,结果等于h[i]*(i+1)。结果要统一加个1。

 

就觉得和栈有关系,但是太久没写了,所以emmm,没用这个方法

 

st算法

可以log(n)获得答案,跟2的倍数有关的。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define ULL unsigned long long
 5 
 6 const LL mod_1=1e9+7;
 7 const LL mod_2=998244353;
 8 
 9 const double eps_1=1e-5;
10 const double eps_2=1e-10;
11 
12 const int maxn=2e5+10;
13 
14 LL h[maxn],r[maxn];
15 LL maxh[maxn][20], ltr[maxn],er[20];
16 
17 int main()
18 {
19     LL n,i,j,k,l;
20     for (i=0;i<20;i++)
21         er[i] = 1<<i;
22 
23     cin>>n;
24     for (i=0;i<n;i++)
25     {
26         cin>>h[i];
27         if (i==0)
28             ltr[i]=h[i];
29         else
30             ltr[i]=max(ltr[i-1],h[i]);
31     }
32         
33     
34     memset(maxh,0,sizeof(maxh));
35     for (i=0;i<=20;i++)
36     {
37         k=1<<i;
38         if (k>n)
39             break;
40         if (i==0)
41         {
42             for (j=0;j<n;j++)
43                 maxh[j][0]=h[j];
44         }
45         else
46         {
47             for (j=k;j<n;j++)
48                 maxh[j][i]=max(maxh[j][i-1],maxh[j-k/2][i-1]);
49             for (j=0;j<k;j++)
50                 maxh[j][i]=ltr[j];
51         }
52     }
53 
54     for (i=0;i<n;i++)
55     {
56         if (i==0)
57         {
58             r[i]=h[i];
59             continue;
60         }
61         
62         if (ltr[i-1]<=h[i])
63         {
64             r[i]=h[i]*(i+1);
65             continue;
66         }
67         
68 
69         j=1;
70         k=0;
71         while (j<=i)    //也可以<号,因为无法到达0的位置
72         {
73             j=j<<1;
74             k++;
75         }
76 
77         l=i-1;
78         while (k--)
79         {
80             if (maxh[l][k]<h[i])
81                 l=l-er[k];
82         }
83         r[i]=r[l] + (i-l)*h[i];
84     }
85 
86     for (i=0;i<n;i++)
87     {
88         cout<<r[i]+1;
89         if (i==n-1)
90             cout<<"\n";
91         else
92             cout<<" ";
93     }
94 
95 
96     return 0;
97 }

 

F

要习惯补beginner赛后的F题。否则,一直少做相对难,比赛上因为做得慢导致稍作的题,技术很难提升甚至倒退

700多个人对。很多了。前面排名的人,人均5分钟切F题

 

 

 

熟悉数据结构中树的特性,很重要。

只要满足:

1. di>=1

2. sum(di)=2N-2

无论树怎么构造都行

 

DP O(N*N) 复杂度超了

可以设置当 di*xi*xi的时候,当xi加1,数值加上di*(2*xi+1),这个数值是递增的

那么一开始所有xi都等于1,然后提供N-2次给xi(i=1~n都可以)加1的机会

每次修改加1数值最小的,用优先队列记录,复杂度O(NlogN)

代码很短,可以写得很快。atcoder特色?

 

另外看到有人用

 1 typedef array<LL,3> par; 2 priority_queue<par, vector<par>, greater<par> > que;  

另外,也可以需要的变量减为两个(x的增量,x),下次变为(x的增量+2*x,x)

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define ULL unsigned long long
 5 
 6 const LL mod_1=1e9+7;
 7 const LL mod_2=998244353;
 8 
 9 const double eps_1=1e-5;
10 const double eps_2=1e-10;
11 
12 const int maxn=2e5+10;
13 
14 LL a[maxn];
15 typedef pair<LL, pair<LL, LL> > par;
16 priority_queue<par,vector<par>,greater<par> > que;
17 par p;
18 
19 int main()
20 {
21     LL n,i,result=0;
22     cin>>n;
23     for (i=0;i<n;i++)
24     {
25         cin>>a[i];
26         que.push( make_pair(a[i]*(2*2-1*1), make_pair(a[i],1) ) );
27         result += a[i];
28     }
29 
30     for (i=0;i<n-2;i++)
31     {
32         p = que.top();
33         result += p.first;
34         p.second.second = p.second.second + 1;
35         p.first = p.second.first * (2*p.second.second + 1);
36         que.pop();
37         que.push(p);
38     }
39 
40     cout<<result;
41     return 0;
42 }

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define ULL unsigned long long
 5 
 6 const LL mod_1=1e9+7;
 7 const LL mod_2=998244353;
 8 
 9 const double eps_1=1e-5;
10 const double eps_2=1e-10;
11 
12 const int maxn=2e5+10;
13 
14 LL a[maxn];
15 typedef pair<LL, pair<LL, LL> > par;
16 priority_queue<par,vector<par>,greater<par> > que;
17 par p;
18 
19 int main()
20 {
21     LL n,i,result=0;
22     cin>>n;
23     for (i=0;i<n;i++)
24     {
25         cin>>a[i];
26         que.push( make_pair(a[i]*(2*2-1*1), make_pair(1,a[i]) ) );
27         result += a[i];
28     }
29 
30     for (i=0;i<n-2;i++)
31     {
32         p = que.top();
33         result += p.first;
34         p.second.first = p.second.first + 1;
35         p.first = p.second.second * (2*p.second.first + 1);
36         que.pop();
37         que.push(p);
38     }
39 
40     cout<<result;
41     return 0;
42 }

 

posted @ 2024-06-24 16:31  congmingyige  阅读(15)  评论(0编辑  收藏  举报