A tb 的区间问题
条件限制只能删除头尾,最后留下的是原数组中任意一段下标连续的长度为 的子区间,前缀和后做差,枚举一遍取最大值即可。
复杂度 。
#include<bits/stdc++.h> #define ll long long using namespace std; const int M=1000005; int k[M]; ll sumt=0; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n,lent,w; cin>>n>>lent>>w; for(int i=1;i<=n;i++) { cin>>k[i]; } if(n<lent) { for(int i=1;i<=n;i++) { sumt+=k[i]; } } else { for(int i=1;i<w;i++) { sumt+=k[i]; } lent-=w; while(lent) { sumt+=k[n]; lent--; n--; } } cout<<sumt<<"\n"; return 0; }
B tb 的字符串问题
方便大家理解,我们可以将 看成 , 看成 , 看成 , 看成 ,其它字符看成 ,原问题就等价于将相邻的括号对尽可能消除,消除到不能消除为止。
用一个栈存此时此刻等待匹配的左括号序列,如果栈非空且遇到与栈顶匹配的右括号,则弹栈并将可消除的括号对数加一,否则将栈清空。
最后字符串总长度减去可消除括号对乘二即可,复杂度 。
#include<bits/stdc++.h> using namespace std; string s,st; const int M=1000005; int tp[M],tot=0,ans=0; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin>>n; cin>>st; s=" "+st; for(int i=1;i<=n;i++) { if(s[i]=='f') tp[++tot]=1; else if(s[i]=='t') tp[++tot]=2; else if(s[i]=='c') { if(tot&&tp[tot]==1) ans++,tot--; else tot=0; } else if(s[i]=='b') { if(tot&&tp[tot]==2) ans++,tot--; else tot=0; } else tot=0; } cout<<n-ans*2<<"\n"; return 0; }
C tb 的路径问题
预估通过率:0.6
手模几组样例,不难发现,
当 时,直接不使用传送阵更优。
当 时:
若使用传送阵:
当 为偶数时, ,则可以走 步到达 并使用传送阵到 ,再走 步到 ,总消耗为 。
由于 ,则其移动到不为 的位置至少需要 步,且从 移动到不为 的位置也至少需要 步,则答案至少为 步。
故此时的答案为 。
当 为奇数时, ,则可以走 步到达 并使用传送阵到 ,再走 步到 ,总消耗为 。
由于 ,则其移动到不为 的位置至少需要 步,且从 移动到不为 的位置也至少需要 步,则答案至少为 步。
而仅有 一个格子数字为 ,无法使用传送阵。
故此时答案为 。
若不使用传送阵:
答案为 ,劣于之前讨论的使用传送阵情况。
综上所述, 时,答案为 , 时,若 为偶数,答案为 ,若 为奇数,答案为 。
#include<iostream> using namespace std; int main() { int x; cin>>x; if(x==1) cout<<0; else if(x==2) cout<<2; else if(x==3) cout<<4; else if(x&1) cout<<6; else cout<<4; return 0; }
D tb 的平方问题
预估通过率:0.3
考虑一个和为平方数的区间,假设其下标为 - ,则其可以对 提供 的贡献。
于是我们可以先求前缀和,再枚举 和 ,判断其是否符合条件,如果符合条件,就对表示答案的差分数组下标为 的位置减一,对下标为 的位置加一,然后对其求前缀和,就是覆盖某个位置符合条件的区间数。
#include<bits/stdc++.h> #define ll long long using namespace std; const int M=1005; ll sumt[M]; int ans[M],a[M],f[M]; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n,q,x; cin>>n>>q; for(int i=1;i<=n;i++) { cin>>a[i]; sumt[i]=sumt[i-1]+a[i]; } for(int i=1;i<=n;i++) { for(int j=i;j<=n;j++) { int bs=sqrt(sumt[j]-sumt[i-1]); if((sumt[j]-sumt[i-1])==1ll*bs*bs) { f[j+1]--; f[i]++; } } } for(int i=1;i<=n;i++) { ans[i]=ans[i-1]+f[i]; } for(int i=1;i<=q;i++) { cin>>x; cout<<ans[x]<<"\n"; } return 0; }
E tb 的数数问题
预估通过率:0.2
先对集合去重。
解一:
考虑如果 是符合条件的数,则集合内其约数的个数应该等于它约数的总个数。
于是外层枚约数,内层枚举其倍数,每个约数如果在集合中出现,则对其倍数有 的贡献,再用线性筛求一下每个数的约数个数,比较一下二者即可。
复杂度均为 。
解二:
考虑如果 符合条件二,设 为质数集,其充要条件为 ,若有 ,有 也符合条件二。
于是考虑线性筛维护 的质因数集,再从小到大枚举 以及 的质因数求解。
复杂度均为 。
解三:
考虑 内哪些数不符合条件,如果 没有出现,那么 的倍数都是不符合条件的数,直接枚举其倍数标记即可,然后输出没被标记的值。
复杂度 。
#include<bits/stdc++.h> using namespace std; const int M=1000005; int p[M],d[M],ts[M],zs[M],f[M],upt[M]; bool vis[M]; void xxs(int n){ d[1]=1; for(int i=2;i<=n;i++) { if(!p[i]) { p[i]=i; zs[++zs[0]]=i; d[i]=2; f[i]=1; } for(int j=1;j<=zs[0]&&i*zs[j]<=n&&p[i]>=zs[j];j++) { if(p[i]!=zs[j]) d[i*zs[j]]=d[i]*d[zs[j]],f[i*zs[j]]=1; else d[i*zs[j]]=d[i]/(f[i]+1)*(f[i]+2),f[i*zs[j]]=f[i]+1; p[i*zs[j]]=zs[j]; } } return ; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n,ans=0,mx=0; cin>>n; for(int i=1;i<=n;i++) { cin>>ts[i]; mx=max(ts[i],mx); vis[ts[i]]=true; } for(int i=1;i<=mx;i++) { if(!vis[i]) continue; for(int j=i;j<=mx;j+=i) { upt[j]++; } } xxs(mx); for(int i=1;i<=mx;i++) { if(vis[i]&&upt[i]==d[i]) ans++; } cout<<ans<<"\n"; return 0; }
F tb 的排列问题
预估通过率:0.1
设 中未出现的数的集合为 。
枚举第 次操作,此时,对于 排列,我们有两种情况:
最终答案为 , 情况的所有贡献求积即可。
#include<bits/stdc++.h> #define ll long long using namespace std; const int M=500005,mod=998244353; int sumt[M],a[M],b[M],id[M],mp[M]; void solve(){ int n,s; ll ans=1; cin>>n>>s; for(int i=1;i<=n;i++) { cin>>b[i]; } for(int i=1;i<=n;i++) { id[i]=0; cin>>a[i]; mp[a[i]]=i; } for(int i=1;i<=n;i++) { if(b[i]==-1) continue; b[i]=mp[b[i]]; id[b[i]]=i; } for(int i=1;i<=n;i++) { sumt[i]=sumt[i-1]; if(b[i]==-1) sumt[i]++; } for(int i=1,cnts=0;i<=n;i++) { if(!id[i]) ans=(ans*(sumt[min(i+s,n)]-cnts))%mod,cnts++; else if(id[i]>i+s) ans=0; } cout<<ans<<"\n"; return ; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T; cin>>T; while(T--) { solve(); } return 0; }