B:
感觉最近几题都用了这种继承的思想。然后就把n方转化为一个递推的问题。
我写了一个跟题解不同的做法是取同余也挺巧妙的。
#include<bits/stdc++.h>
using namespace std;
#define CI const int&
#define int long long
const int maxn=2e5+10;
int a[maxn],vis[maxn],cnt[maxn];
void solve(){
int n,x;cin>>n>>x;
for(int i=0;i<=n;i++)vis[i]=0,cnt[i]=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]<=n)vis[a[i]]++;
}
for(int i=0;i<=n;i++){
if(vis[i]==0&&cnt[i%x]==0){
return cout<<i<<endl,void();
}
if(vis[i])vis[i]--;
else cnt[i%x]--;
if(vis[i]>0)cnt[i%x]+=vis[i];
}
}
signed main(){
int t;cin>>t;while(t--)solve();
}
C1:
甚至不需要发现性质也能写的贪心。
C2:
性质其实就是找一个值在b中第一次出现的顺序是否与a排列顺序相符。
由此很容易发现是严格递增的,然后维护手段也很多。线段树写起来很简单,也算是权值线段树了。
就是得套个set。然后ai,bi还有下标的关系要考虑清楚,还有删除操作。
#include<bits/stdc++.h>
using namespace std;
#define CI const int&
#define int long long
#define ls(x) (x*2)
#define rs(x) (x*2+1)
const int maxn=1e6+10;
int a[maxn],b[maxn],c[maxn],n,m,q;
int mx[maxn],mn[maxn],t[maxn];
set<int>st[maxn];
void push_up(int p){
mx[p]=max(mx[ls(p)],mx[rs(p)]);
mn[p]=min(mn[ls(p)],mn[rs(p)]);
if(t[ls(p)]&&t[rs(p)]&&mx[ls(p)]<mn[rs(p)])t[p]=1;
else t[p]=0;
}
void upd(int p,int l,int r,int q,int k){
//cout<<l<<r<<endl;
if(l==r){
mx[p]=mn[p]=k;t[p]=1;
return;
}
int mid=(l+r)/2;
if(q<=mid)upd(ls(p),l,mid,q,k);
else upd(rs(p),mid+1,r,q,k);
push_up(p);
//cout<<p<<' '<<t[p]<<'k'<<endl;
}
void solve(){
cin>>n>>m>>q;
for(int i=1;i<=n;i++)st[i].clear();
for(int i=1;i<=n;i++){
cin>>a[i],c[a[i]]=i;
if(st[a[i]].size()==0)st[a[i]].insert(m+i);
}
for(int i=1;i<=m;i++){
cin>>b[i];st[b[i]].insert(i);
}
set<int>::iterator it;
for(int i=1;i<=n;i++){
it=st[a[i]].begin(),upd(1,1,n,c[a[i]],*it);
}
if(t[1])cout<<"Ya"<<endl;
else cout<<"TIDAK"<<endl;
while(q--){
int i,j;cin>>i>>j;
st[b[i]].erase(i);//
upd(1,1,n,c[b[i]],*st[b[i]].begin());
b[i]=j;
st[j].insert(i);
it=st[j].begin();
upd(1,1,n,c[j],*it);
if(t[1])cout<<"Ya"<<endl;
else cout<<"TIDAK"<<endl;
}
}
signed main(){
int t;cin>>t;while(t--)solve();
}
标签:977,int,st,maxn,ls,C2,Div,mx,define
From: https://www.cnblogs.com/lyrrr/p/18455755