版权声明:转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82387428
传送门:CodeforcesRound1037
这场的题解,标程都不太友好啊。。。
E. Trips
题解
考虑倒着回答询问,假设所有人都将去旅行,再考虑不满足条件的逐一删去。
表示结点
在旅行网中的度数(已经删去的点不再考虑),用
存
,按
升序排列。
不断弹出旅行网中度数
的点,再逐一更新与之相连的点的度数即可,每次操作断掉一条边,记录
中剩余的点数即为答案。
代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define sc second
using namespace std;
const int N=2e5+10;
int n,m,k,d[N],ans[N],in[N],sum;
pii rl[N],tp;
vector<pii>g[N];
set<pii>S;
int main(){
int i,j,q,x,y;
scanf("%d%d%d",&n,&m,&k);
sum=n;
for(i=1;i<=m;++i){
scanf("%d%d",&x,&y);
rl[i].fi=x;rl[i].sc=y;
d[x]++;d[y]++;
g[x].push_back(mkp(y,i));
g[y].push_back(mkp(x,i));
}
for(i=1;i<=n;++i)
in[i]=1,S.insert(mkp(d[i],i));
for(i=m;i;--i){
if(!sum) {ans[i]=0;continue;}
set<pii>::iterator iter=S.begin();
for(tp=*iter;(!S.empty()) && ((!in[tp.sc])||(d[tp.sc]!=tp.fi)||(tp.fi<k));){
if(!in[tp.sc] || (d[tp.sc]!=tp.fi)) S.erase(iter);
else{
S.erase(iter);
in[tp.sc]=0;sum--;
for(q=g[tp.sc].size()-1;~q;--q){
j=g[tp.sc][q].fi;if(!in[j] || g[tp.sc][q].sc>i) continue;
d[j]--;S.insert(mkp(d[j],j));
}
}
if(S.empty()) break;
else iter=S.begin(),tp=*iter;
}
ans[i]=sum;x=rl[i].fi;y=rl[i].sc;
if(in[x] && in[y])
{d[x]--;d[y]--;S.insert(mkp(d[x],x));S.insert(mkp(d[y],y));}
}
for(i=1;i<=m;++i) printf("%d\n",ans[i]);
}
F. Maximum Reduction
题解
一个递归的过程显然可以转化为统计每个值的出现次数。
考虑单调栈处理出
,区间
表示
为满足
的最大区间。
对于第
个数
,出现次数等价于长度为
的左右端点在
范围内,且覆盖点
的区间个数。
设
为长度如上的左右端点出现在
范围内的区间个数,显然是一个等差数列可以算出(这里预处理了一下),则
的出现次数可以通过容斥得到:
。
复杂度
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,mod=1e9+7;
int n,k,a[N],q[N],top;
int L[N],R[N],v[N],s[N],tot;
int ans;
inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int cal(int l,int r)
{
if(l+k-1>r) return 0;
int len=r-l+1,bs=len/(k-1);
if(v[bs]>len) bs--;
return ad(dc(mul(len,bs),s[bs]),bs);
}
int main(){
int i,j;
scanf("%d%d",&n,&k);
for(i=1;i<=n;++i) scanf("%d",&a[i]),L[i]=1,R[i]=n;
for(i=1;i<=n;++i){
for(;top && a[q[top]]<a[i];top--) R[q[top]]=i-1;
L[i]=q[top]+1;q[++top]=i;
}
for(i=1;;++i) {v[i]=i*k-i+1;if(v[i]>n) break;}
tot=i-1;
for(i=1;i<=tot;++i) s[i]=ad(s[i-1],v[i]);
for(i=1;i<=n;++i)
ans=ad(ans,mul(a[i],dc(cal(L[i],R[i]),ad(cal(L[i],i-1),cal(i+1,R[i])))));
printf("%d\n",ans);
}
G. A Game on Strings
题解
博弈论相关。处理出每个相同字符之间的区间的
函数和其前缀后缀的
函数。把所有需要处理的区间按长度排序,记忆化搜索预处理。每次询问整块和前后缀的
函数异或得到答案。
复杂度
(似乎忽略了记忆化搜索的复杂度?)
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
int n,m,id[N],num[26];
int ql[26][N],qr[26][N],fl[26][N],fr[26][N];
int w[26][N],pos[N],cnt,tot;
char s[N];
struct L{
int len,l,r;
L(){}
L(int LEN,int QL,int QR){len=LEN;l=QL;r=QR;}
}le[N*30];
inline bool cmp(const L&x,const L&y){
if(x.len!=y.len) return x.len<y.len;
if(x.l!=y.l) return x.l<y.l;
return x.r<y.r;
}
inline int get(int l,int r)
{
int i,j,st,ed,res=0,nw;
for(i=0;i<26;++i)
if(qr[i][l]<=r){
nw=0;
st=qr[i][l];ed=ql[i][r];
for(j=id[st]+1;j<=id[ed];++j) nw^=w[i][j];
if(l<st){
if(fl[i][l]==-1) fl[i][l]=get(l,st-1);
nw^=fl[i][l];
}
if(ed<r){
if(fr[i][r]==-1) fr[i][r]=get(ed+1,r);
nw^=fr[i][r];
}
res|=(1<<nw);
}
for(i=0;;++i)
if(!((res>>i)&1)) return i;
}
inline int ask(int l,int r)
{
int i,j,st,ed,res=0,nw;
for(i=0;i<26;++i)
if(qr[i][l]<=r){
st=qr[i][l];ed=ql[i][r];
nw=(w[i][id[st]]^w[i][id[ed]]);
if(l<st){
if(fl[i][l]==-1) fl[i][l]=ask(l,st-1);
nw^=fl[i][l];
}
if(ed<r){
if(fr[i][r]==-1) fr[i][r]=ask(ed+1,r);
nw^=fr[i][r];
}
res|=(1<<nw);
}
for(i=0;;++i)
if(!((res>>i)&1)) return i;
}
int main(){
int i,j,alp,l,r;
memset(fl,0xff,sizeof(fl));
memset(fr,0xff,sizeof(fr));
scanf("%s",s+1);
n=strlen(s+1);
for(i=1;i<=n;++i)
id[i]=++num[s[i]-'a'];
for(i=0;i<26;++i) ql[i][0]=0,qr[i][n+1]=n+1;
for(i=1;i<=n;++i){
for(j=0;j<26;++j) ql[j][i]=ql[j][i-1];
ql[s[i]-'a'][i]=i;
}
for(i=n;i;--i){
for(j=0;j<26;++j) qr[j][i]=qr[j][i+1];
qr[s[i]-'a'][i]=i;
}
for(i=0;i<26;++i){
for(cnt=0,j=1;j<=n;++j) if(s[j]-'a'==i) pos[++cnt]=j;
for(j=1;j<cnt;++j)
le[++tot]=L(pos[j+1]-pos[j]-1,pos[j],pos[j+1]);
}
sort(le+1,le+tot+1,cmp);//le+tot->le+tot+1
for(i=1;i<=tot;++i) if(le[i].r>le[i].l+1){
j=le[i].r;
w[s[j]-'a'][id[j]]=get(le[i].l+1,j-1);
}
for(i=0;i<26;++i)
for(j=2;j<=num[i];++j)
w[i][j]^=w[i][j-1];
scanf("%d",&m);
for(;m;--m){
scanf("%d%d",&l,&r);
puts(ask(l,r)?"Alice":"Bob");
}
}