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();
}