序列更新
给定两个长度为 的序列:
和
需要依次执行 次操作。每次操作给出一个整数 ,按下标关系维护序列更新。
输入
第一行包含一个正整数 ,表示测试数据组数,满足 。
每组数据第一行包含两个正整数 ,分别表示序列长度和操作次数,满足 。
第二行包含 个正整数 ,满足 。
第三行包含 个正整数 ,满足 。
接下来 行,每行包含一个整数 。
分析
按 的大小分类处理:
- 当 较大时,直接暴力更新。
- 当 较小时,预处理对应的余数类,用 更新 。
设当前大于阈值 的元素数量为 。如果连续若干次操作都没有命中这些元素,其概率可以近似写成 的幂次,因此期望次数为:
令 ,则:
由等比数列求和可得:
在实现上,可以用根号分治平衡两部分复杂度。总复杂度近似为:
当 时,取 最优,复杂度约为 。
最优 K 子段
分析
首先二分答案。对于每个候选值 ,在 check 中贪心维护最小值不小于 的最多子段数量。
从左端点开始枚举,通过维护一个前缀集合 set,保证以位置 结尾的子段满足:
接着需要估计:对每个 ,暴力枚举 set 中满足 为质数的元素,复杂度是多少。
因为 中质数个数约为 ,随机命中质数间隔的期望为 ,所以单次枚举的期望复杂度为 。
最终总时间复杂度约为:
序列更新代码
#include
using namespace std;
#define ll long long
#define pb push_back
#define int long long
#define PII pair
#define PI acos(-1)
#define s second
#define f first
#define Bint __int128
#define all(x) x.begin(),x.end()
#define isdigit(x) ((x) >= '0' && (x) n)x-=n;
}
inline void modify(int x,int y){
fix(x);
fix(y);
if(a[x]>=b[y])return ;
sum+=b[y]-a[x];
a[x]=b[y];
}
void solve(){
ca=0,cb=0;
cin>>n>>q;
sum=0;
for(int i=1;i>a[i];
for(int i=1;i>b[i],c[i]=b[i];
int s=sqrt(n);
s=max(s,(int)1);
sort(c+1,c+1+n);
for(int i=1;is)B[cb++]=i;
}
while(q--){
int k;cin>>k;
for(int i=0;is)swap(A[i],A[--ca]);else i++;
}
for(int i=0;i>T;
while(T--){
solve();
}
return 0;
}
最优 K 子段代码
#include
using namespace std;
#define ll long long
#define pb push_back
#define int long long
#define PII pair
#define PI acos(-1)
#define s second
#define f first
#define Bint __int128
#define all(x) x.begin(),x.end()
#define isdigit(x) ((x) >= '0' && (x) b;
void get_primes(int n)
{
st[1]=1;
for (int i = 2; i f>=x){
bool f=0;
for(auto &[p,pos]:b){
if(s-p>=x&&!st[i-pos]){
f=1;
break;
}
else if(s-p>n>>k;
for(int i=1;i>a[i],pre[i]=a[i]+pre[i-1];
int l=0,r=0;
for(int i=1;i=0)r+=a[i];
else l+=a[i];
while(l>1;
if(check(mid))l=mid;
else r=mid-1;
}
if(check(l))
cout>T;
while(T--){
solve();
}
return 0;
}