C. Fixed Point Removal
我们预处理一个数组,\(p_i\) 表示若想要删除 \(i\) 的最晚起点。
显然若 \(a_i=i\) 则 \(p_i=i\),若 \(a_i<i\) 则 \(p_i\) 为前面的第 \(i-a_i\) 大,这可以树状数组上二分做。
离线询问,每个询问即区间 \([l,r]\) 之间 \(p_i>=l\) 的个数,树状数组可做。
代码懒得写了,蒯了 \(verdandi\) 的用着:
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m;
int a[maxn],ans[maxn],tr[maxn];
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define pb push_back
vector<pii>v[maxn];
void update(int x,int v){
for(int i=x;i<=n;i+=i&(-i))tr[i]+=v;
}
int query(int x){
int res=0;
for(int i=x;i;i-=i&(-i))res+=tr[i];
return res;
}
int getkth(int k){
int res=0;
for(int i=18;i>=0;i--)
if(res+(1<<i)<=n&&k>tr[res+(1<<i)])
k-=tr[res+(1<<i)],res+=(1<<i);
return res+1;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1,x,y;i<=m;i++){
x=read()+1,y=n-read();
if(x<=y)v[y].pb(mkp(x,i));
}
for(int i=1;i<=n;i++){
if(i-a[i]>=0){
int pos=getkth(a[i]);
update(min(i+1,pos),1);
}else update(1,1);
for(int j=0;j<v[i].size();j++)
ans[v[i][j].se]=i-query(v[i][j].fi);
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
D. Game of Pairs
题意:交互,给定 \(n\) ,选择先后手,先手需要构造将 \(1\) 到 \(2n\) 分为 \(n\) 对,使得不存在一种方案从每对中选一个和为 \(2n\) 的倍数;后手需要在交互库给定的 \(n\) 对中每对选出一个数使得和为 \(2n\) 的倍数。
考虑何时先手必胜。若 \(n=1\) 时显然先手负,\(n=2\) 时先手胜,不妨猜测 \(n\) 为偶数时先手必胜。事实的确如此,我们把 \(i\) 和 \(i+n\) 放在一对,那么选出来的数必定是 \(\frac 12 n(n+1)+kn\) 不是 \(2n\) 的倍数。再考虑为什么 \(n\) 为奇数时必负。我们还是希望取出来的数能够是模 \(n\) 意义下的完全剩余系,这样如果我们取出的方案不行,则留下的一定行。考虑每对间连边,\(i\) 和 \(i+n\) 之间连边,每个点的度数均为 \(2\) ,故会形成若干简单偶环,此时将图二分图染色,不难发现 \(i\) 和 \(i+n\) 总不同色,故方案合法。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=1e6+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,p[maxn],G[maxn],las[maxn],col[maxn],t[maxn],S;
inline void dfs(int x,int cur){
if(col[x])return;col[x]=cur;
dfs(G[x],3-cur);dfs((x+n-1)%(n+n)+1,3-cur);
}
int main(){
n=read();
if(n%2==0){
cout<<"First"<<endl;
for(int i=1;i<=n;i++)cout<<i<<" ";
for(int i=1;i<=n;i++)cout<<i<<" ";
cout<<endl;
}else{
cout<<"Second"<<endl;
for(int i=1;i<=n+n;i++){
p[i]=read();
if(las[p[i]])
G[las[p[i]]]=i,G[i]=las[p[i]];
else las[p[i]]=i;
}
for(int i=1;i<=n+n;i++)
if(!col[i])dfs(i,1);
for(int i=1;i<=n+n;i++)
if(col[i]==1)S=(S+i)%(n+n);
int flg=(S?2:1);
for(int i=1;i<=n+n;i++)
if(col[i]==flg)printf("%d ",i);
cout<<endl;
}
return 0;
}//