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
设 中未出现的数的集合为
。
枚举第 次操作,此时,对于
排列,我们有两种情况:
最终答案为 不属于 P : 此时
所对应的数如果在
中的初始位置就大于了
,则一定不存在操作使之复位,否则,其初始位置如果在
到
,则一定通过置换操作移动到了
到
,则此次置换操作一定可以将其复位,能复位贡献为1,否则贡献为0。
属于 P : 此时
可以填入
到
中所有为
的位置,因为通过之前的操作,
到
的位置均已复位,则之前未填的为
的位置通过置换操作至多移到了
的位置,于是一定可以填充,此时贡献为
,
为已经填充的
个数,
为
数组中下标为
到
中
的个数;
,
情况的所有贡献求积即可。
#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;
}

京公网安备 11010502036488号