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 }