RT

2018.12.27

i207M:BZOJ 4695 最假女选手

以维护最大值为例,记录最大值和严格次大值和最大值的出现次数,然后取min的时候递归到小于最大值但大于次大值修改,这个就是最重要的地方,剩下的就是码码码调调调

 #include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,M=,inf=1e9;
int maxx[M],smax[M],cnt1[M];
int mini[M],smin[M],cnt2[M];
int a[N],laz[M]; long long val[M];
int n,m,f,op,t1,t2,t3;
void read(int &x)
{
x=,f=; char ch=getchar();
while(!isdigit(ch))
f|=ch=='-',ch=getchar();
while(isdigit(ch))
x=(x<<)+(x<<)+(ch^),ch=getchar();
x=f?-x:x;
}
void write(long long x)
{
if(x>) write(x/);
putchar(x%|);
}
void w(long long x)
{
if(x<) putchar('-'),x=-x;
write(x),puts("");
}
void Pushup(int nde)
{
int ls=*nde,rs=*nde+;
val[nde]=val[ls]+val[rs];
if(maxx[ls]==maxx[rs])
maxx[nde]=maxx[ls],smax[nde]=max(smax[ls],smax[rs]),cnt1[nde]=cnt1[ls]+cnt1[rs];
else
{
if(maxx[ls]<maxx[rs]) swap(ls,rs);
maxx[nde]=maxx[ls],smax[nde]=max(smax[ls],maxx[rs]),cnt1[nde]=cnt1[ls];
}
if(mini[ls]==mini[rs])
mini[nde]=mini[ls],smin[nde]=min(smin[ls],smin[rs]),cnt2[nde]=cnt2[ls]+cnt2[rs];
else
{
if(mini[ls]>mini[rs]) swap(ls,rs);
mini[nde]=mini[ls],smin[nde]=min(smin[ls],mini[rs]),cnt2[nde]=cnt2[ls];
}
}
void Apply(int nde,int l,int r,int tsk,int opt)
{
if(!opt)
{
maxx[nde]+=tsk,smax[nde]+=tsk;
mini[nde]+=tsk,smin[nde]+=tsk;
laz[nde]+=tsk,val[nde]+=1ll*tsk*(r-l+);
}
else if(opt==)
{
val[nde]+=1ll*(tsk-mini[nde])*cnt2[nde];
mini[nde]=tsk,maxx[nde]=max(maxx[nde],tsk);
if(mini[nde]==maxx[nde])
{
val[nde]=1ll*tsk*(r-l+);
cnt1[nde]=cnt2[nde]=r-l+;
smax[nde]=-inf,smin[nde]=inf;
}
else smax[nde]=max(smax[nde],tsk);
}
else if(opt==)
{
val[nde]-=1ll*(maxx[nde]-tsk)*cnt1[nde];
maxx[nde]=tsk,mini[nde]=min(mini[nde],tsk);
if(mini[nde]==maxx[nde])
{
val[nde]=1ll*tsk*(r-l+);
cnt1[nde]=cnt2[nde]=r-l+;
smax[nde]=-inf,smin[nde]=inf;
}
else smin[nde]=min(smin[nde],tsk);
}
}
void Release(int nde,int l,int r)
{
int mid=(l+r)/,ls=*nde,rs=*nde+;
if(laz[nde])
{
Apply(ls,l,mid,laz[nde],);
Apply(rs,mid+,r,laz[nde],),laz[nde]=;
}
if(mini[ls]<mini[nde]&&smin[ls]>mini[nde]) Apply(ls,l,mid,mini[nde],);
if(mini[rs]<mini[nde]&&smin[rs]>mini[nde]) Apply(rs,mid+,r,mini[nde],);
if(maxx[ls]>maxx[nde]&&smax[ls]<maxx[nde]) Apply(ls,l,mid,maxx[nde],);
if(maxx[rs]>maxx[nde]&&smax[rs]<maxx[nde]) Apply(rs,mid+,r,maxx[nde],);
}
void Create(int nde,int l,int r)
{
if(l==r)
{
maxx[nde]=mini[nde]=val[nde]=a[l];
smax[nde]=-inf,smin[nde]=inf,cnt1[nde]=cnt2[nde]=;
}
else
{
int mid=(l+r)/,ls=*nde,rs=*nde+;
Create(ls,l,mid),Create(rs,mid+,r),Pushup(nde);
}
}
void Add(int nde,int l,int r,int nl,int nr,int tsk)
{
if(l>nr||r<nl)
return ;
else if(l>=nl&&r<=nr)
Apply(nde,l,r,tsk,);
else
{
int mid=(l+r)/,ls=*nde,rs=*nde+; Release(nde,l,r);
Add(ls,l,mid,nl,nr,tsk),Add(rs,mid+,r,nl,nr,tsk),Pushup(nde);
}
}
void Maxi(int nde,int l,int r,int nl,int nr,int tsk)
{
if(l>nr||r<nl||mini[nde]>=tsk)
return ;
else if(l>=nl&&r<=nr&&smin[nde]>tsk)
Apply(nde,l,r,tsk,);
else
{
int mid=(l+r)/,ls=*nde,rs=*nde+; Release(nde,l,r);
Maxi(ls,l,mid,nl,nr,tsk),Maxi(rs,mid+,r,nl,nr,tsk),Pushup(nde);
}
}
void Mini(int nde,int l,int r,int nl,int nr,int tsk)
{
if(l>nr||r<nl||maxx[nde]<=tsk)
return ;
else if(l>=nl&&r<=nr&&smax[nde]<tsk)
Apply(nde,l,r,tsk,);
else
{
int mid=(l+r)/,ls=*nde,rs=*nde+; Release(nde,l,r);
Mini(ls,l,mid,nl,nr,tsk),Mini(rs,mid+,r,nl,nr,tsk),Pushup(nde);
}
}
long long Query(int nde,int l,int r,int nl,int nr,int opt)
{
if(l>nr||r<nl)
{
if(!opt) return ;
else if(opt==) return -inf;
else if(opt==) return inf;
}
else if(l>=nl&&r<=nr)
{
if(!opt) return val[nde];
else if(opt==) return maxx[nde];
else if(opt==) return mini[nde];
}
else
{
int mid=(l+r)/,ls=*nde,rs=*nde+; Release(nde,l,r);
if(!opt) return Query(ls,l,mid,nl,nr,opt)+Query(rs,mid+,r,nl,nr,opt);
else if(opt==) return max(Query(ls,l,mid,nl,nr,opt),Query(rs,mid+,r,nl,nr,opt));
else if(opt==) return min(Query(ls,l,mid,nl,nr,opt),Query(rs,mid+,r,nl,nr,opt));
}
}
int main()
{
read(n); register int i;
for(i=;i<=n;i++) read(a[i]);
Create(,,n),read(m);
for(i=;i<=m;i++)
{
read(op),read(t1),read(t2);
if(op==) read(t3),Add(,,n,t1,t2,t3);
else if(op==) read(t3),Maxi(,,n,t1,t2,t3);
else if(op==) read(t3),Mini(,,n,t1,t2,t3);
else if(op==) w(Query(,,n,t1,t2,));
else if(op==) w(Query(,,n,t1,t2,));
else if(op==) w(Query(,,n,t1,t2,));
}
return ;
}

AubRain:CF993E Nikita and Order Statistics

转换成01序列变成了子区间和问题,然后对值域上的序列反过来做卷积

 #include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,M=;
const double pai=acos(-);
struct cpx
{
double x,y;
}a[N],b[N];
cpx operator + (cpx c1,cpx c2)
{
return (cpx){c1.x+c2.x,c1.y+c2.y};
}
cpx operator - (cpx c1,cpx c2)
{
return (cpx){c1.x-c2.x,c1.y-c2.y};
}
cpx operator * (cpx c1,cpx c2)
{
double x1=c1.x,x2=c2.x,y1=c1.y,y2=c2.y;
return (cpx){x1*x2-y1*y2,x1*y2+x2*y1};
}
double Sin[M],Cos[M];
int rev[N],lgg[N];
int n,x,m,nm,rd,sum;
void write(long long x)
{
if(x>) write(x/);
putchar(x%|);
}
void Prework()
{
scanf("%d%d",&n,&x),a[].x=;
for(int i=;i<=n;i++)
{
scanf("%d",&rd);
sum+=rd<x,a[sum].x+=;
}
for(int i=;i<=n;i++)
b[n-i].x=a[i].x;
nm=n,n*=,m=,lgg[]=; while(m<=n) m<<=;
for(int i=;i<=m;i++)
rev[i]=(rev[i>>]>>)+(i&)*(m>>);
for(int i=;i<=m;i++)
lgg[i]=lgg[i>>]+;
for(int i=;i<=;i++)
Sin[i]=sin(*pai/(<<i)),Cos[i]=cos(*pai/(<<i));
}
void Trans(cpx *c,int t)
{
for(int i=;i<m;i++)
if(rev[i]>i) swap(c[rev[i]],c[i]);
for(int i=;i<=m;i<<=)
{
int len=i>>;
cpx omg={Cos[lgg[i]],Sin[lgg[i]]*t};
for(int j=;j<m;j+=i)
{
cpx ori={,},tmp;
for(int k=j;k<j+len;k++,ori=ori*omg)
tmp=ori*c[k+len],c[k+len]=c[k]-tmp,c[k]=c[k]+tmp;
}
}
if(t==-) for(int i=;i<=m;i++) c[i].x/=m;
}
long long Round(double x)
{
return (long long)(x+0.5);
}
int main()
{
Prework();
Trans(a,),Trans(b,);
for(int i=;i<=m;i++) a[i]=a[i]*b[i];
Trans(a,-);
write(Round((a[nm].x-nm-)/)),putchar(' ');
for(int i=nm+;i<=n;i++)
write(Round(a[i].x)),putchar(' ');
return ;
}

ywy_c_asm:HNOI 2010 物品调度

第一问比较难,最暴力的做法是对每个位置$O(n)$枚举,然后发现$x*d$在模剩余系下会出环,于是用并查集优化,然后O(能过)(网上原来的题解都是这么写的)

可惜ztb随手卡了,数据是 1 100000 1 1 100000 100000 100000,解决方法是把环们也用并查集连起来或者用set找

第二问把所有环找出来,有空位的环答案是len-1,没有空位就把空位移过去再移出来,答案是len+1

 #include<set>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
int T,n,q,p,m,d,s,g,emp,cnt,ans;
int aset[N],pos[N],vis[N],c[N];
set<pair<int,int> > st;
set<pair<int,int> >::iterator it;
int Gcd(int a,int b)
{
return b?Gcd(b,a%b):a;
}
int Finda(int x)
{
return x==aset[x]?x:aset[x]=Finda(aset[x]);
}
void Init()
{
memset(vis,,sizeof vis),st.clear();
scanf("%d%d%d%d%d%d",&n,&s,&q,&p,&m,&d);
for(int i=;i<n;i++) c[i]=(1ll*c[i-]*q+p)%m;
for(int i=;i<n;i++) aset[i]=i,c[i]%=n;
g=Gcd(d,n),emp=s%g,cnt=n/g,ans=;
for(int i=;i<g;i++)
if(i==emp)
{
aset[pos[]=s]=Finda((s+d)%n);
if(cnt>) st.insert(make_pair(i,cnt-));
}
else st.insert(make_pair(i,cnt));
}
int main()
{
scanf("%d",&T);
while(T--)
{
Init();
for(int i=;i<n;i++)
{
it=st.lower_bound(make_pair(c[i]%g,));
if(it!=st.end())
{
int ps=it->first,ct=it->second;
st.erase(it); if(ct>) st.insert(make_pair(ps,ct-));
pos[i]=Finda((ps+c[i]-c[i]%g)%n),aset[pos[i]]=Finda((pos[i]+d)%n);
}
else
{
it=st.begin(); int ps=it->first,ct=it->second;
st.erase(it); if(ct>) st.insert(make_pair(ps,ct-));
pos[i]=Finda((ps+(c[i]/g+)*g)%n),aset[pos[i]]=Finda((pos[i]+d)%n);
}
}
for(int i=;i<n;i++)
if(!vis[i])
{
int nw=i,len=;
while(!vis[nw])
len++,vis[nw]=true,nw=pos[nw];
if(!i) ans+=len-;
else if(len>) ans+=len+;
}
printf("%d\n",ans);
}
return ;
}

Newwen:洛谷 4299 首都

LCT维护子树大小,用并查集维护重心,每次连起来之后根据重心的性质新的重心一定在旧的重心连成的链上,然后把这条链拎出来在(Splay)上面走即可

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,inf=1e9;
int fth[N],son[N][],siz[N],rev[N];
int val[N],aset[N],sizz[N],stk[N];
int n,m,t1,t2,top,xrr;
char op[];
int Finda(int x)
{
return x==aset[x]?x:aset[x]=Finda(aset[x]);
}
void Pushup(int nde)
{
int lson=son[nde][],rson=son[nde][];
siz[nde]=siz[lson]+siz[rson]+sizz[nde]+;
}
void Release(int nde)
{
if(rev[nde])
{
int &lson=son[nde][],&rson=son[nde][];
swap(lson,rson),rev[lson]^=,rev[rson]^=,rev[nde]^=;
}
}
bool Nottop(int nde)
{
int fa=fth[nde];
return son[fa][]==nde||son[fa][]==nde;
}
void Rotate(int nde)
{
int fa=fth[nde],gr=fth[fa],isl=nde==son[fa][];
if(Nottop(fa)) son[gr][fa==son[gr][]]=nde;
fth[nde]=gr,fth[fa]=nde,fth[son[nde][isl]]=fa;
son[fa][isl^]=son[nde][isl],son[nde][isl]=fa;
Pushup(fa),Pushup(nde);
}
void Splay(int nde)
{
stk[top=]=nde;
for(int i=nde;Nottop(i);i=fth[i])
stk[++top]=fth[i];
while(top) Release(stk[top--]);
while(Nottop(nde))
{
int fa=fth[nde],gr=fth[fa];
if(Nottop(fa))
Rotate(((son[fa][]==nde)==(son[gr][]==fa))?fa:nde);
Rotate(nde);
}
}
void Access(int nde)
{
int mem=nde,lst=;
while(nde)
{
Splay(nde),sizz[nde]+=siz[son[nde][]]-siz[lst];
son[nde][]=lst,Pushup(nde),lst=nde,nde=fth[nde];
}
Splay(mem);
}
void Turnroot(int nde)
{
Access(nde),rev[nde]^=;
}
int Getroot(int nde)
{
Access(nde);
while(son[nde][])
nde=son[nde][];
return nde;
}
void Split(int x,int y)
{
Turnroot(x),Access(y);
}
void Link(int x,int y)
{
Turnroot(x);
if(Getroot(y)!=x)
sizz[y]+=siz[x],fth[x]=y,Pushup(y);
}
int Change(int nde)
{
int sum1=,sum2=,ret=inf,oe=siz[nde]%,haf=siz[nde]/;
while(nde)
{
Release(nde);
int lson=son[nde][],rson=son[nde][];
int nsm1=sum1+siz[lson],nsm2=sum2+siz[rson];
if(nsm1<=haf&&nsm2<=haf)
{
if(oe) {ret=nde; break;}
else ret=min(ret,nde);
}
if(nsm1<=nsm2) sum1+=siz[lson]+sizz[nde]+,nde=rson;
else sum2+=siz[rson]+sizz[nde]+,nde=lson;
}
Splay(ret);
return ret;
}
void Linka(int x,int y)
{
int fx=Finda(x),fy=Finda(y);
Link(x,y),Split(fx,fy); int newc=Change(fy);
aset[fx]=aset[fy]=aset[newc]=newc,xrr^=fx^fy^newc;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
xrr^=i,aset[i]=i;
while(m--)
{
scanf("%s",op);
if(op[]=='X')
printf("%d\n",xrr);
else if(op[]=='A')
scanf("%d%d",&t1,&t2),Linka(t1,t2);
else
{
scanf("%d",&t1);
printf("%d\n",Finda(t1));
}
}
return ;
}

2018.12.29

shadowice1984:ZJOI 2018 线图

怪不得ZJOI 2018被骂,谁**考试的时候写这种题啊=。=

(本题未被制杖博主实现,同时这都是框架,具体实现......算了orz shadowice1984)

手玩发现(雾 k阶线图里原图中大小为$k+1$的联通块会合成一个点

我们考虑这样求答案:①拆联通块 ②数联通块 ③算联通块的贡献

①拆联通块

其实就是在枚举有根树(无根树也一样,但是据说有根树好写)

考虑用欧拉序+树哈希,因为爆搜可得本质不同的合法有根树只有1k多一点,所以问题不大

②数联通块

DP,设$dp(i,j)$表示$i$的子树当中匹配当前树当中$j$的子树有多少种方案,然后用一个临时数组存一下来转移

发现会重,因为被算了同一层的点数的阶乘,然后把这个去掉才对

③算联通块的贡献

这里我得先说思路,思路是玩四阶线图的公式(需要图的具体形态,然后得出一个答案)然后暴力跑五阶之后套公式(有毒

一阶线图:边数

二/三阶线图:枚举点

四阶线图:枚举边

具体的不推了

咕咕咕

制杖的ydnhaha的交流题目的解题

X_stream:CF724E Goods transportation

首先可以很容易的建出一张网络流图:把城市拆点,原点向每个城市连购买量的边,每个城市向后面的城市连c的边,每个城市再向汇点连卖出量的边,然后跑最大流

发现图太大了建不出来,考虑用其他方法求。首先转化为最小割,然后设$dp[i][j]$表示前$i$个点最终有$j$个点未与源点分割,然后$n^2$dp即可

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
long long n,c,x,ans=1e18;
long long p[N],q[N],dp[][N];
int main()
{
scanf("%lld%lld",&n,&c);
for(int i=;i<=n;i++) scanf("%lld",&p[i]);
for(int i=;i<=n;i++) scanf("%lld",&q[i]);
memset(dp,0x3f,sizeof dp),dp[][]=;
for(int i=;i<=n;i++,x^=)
{
memset(dp[x],0x3f,sizeof dp[x]);
for(int j=;j<=i;j++)
{
dp[x][j]=min(dp[x][j],dp[x^][j]+p[i]+c*j);
if(j) dp[x][j]=min(dp[x][j],dp[x^][j-]+q[i]);
}
}
for(int i=;i<=n;i++) ans=min(ans,dp[x^][i]);
printf("%lld",ans);
return ;
}

*Miracle*:AT2764 Sightseeing Plan

首先我们可以求点到点的方案数,然后我们把一个点到一个矩形的方案求个和(容斥)发现是个类似点到点的组合数。

也就是说现在我们可以O(1)求点到矩形的方案数。我们可以在中间枚举一个点,然后求到两边的方案数乘起来,但是这是$n^2$的,考虑优化

我们考虑那个点到矩形组合数的另一个意义,即点到点的方案。那我们可以分开枚举中间矩形的两条邻边上的点,每个对点间都有很多路径,我们定义路径的权值等于点数然后分开求和即可。

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,M=2e6;
const long long mod=1e9+;
long long fac[N],inv[N],xx[],yy[],ans;
long long qpow(long long x,long long k)
{
if(k==) return x;
long long tmp=qpow(x,k/);
return k%?tmp*tmp%mod*x%mod:tmp*tmp%mod;
}
void Prework()
{
register int i; fac[]=inv[]=;
for(i=;i<=M;i++) fac[i]=fac[i-]*i%mod;
inv[M]=qpow(fac[M],mod-);
for(i=M-;i;i--) inv[i]=inv[i+]*(i+)%mod;
for(i=;i<=;i++) scanf("%lld",&xx[i]);
for(i=;i<=;i++) scanf("%lld",&yy[i]);
}
long long C(int a,int b)
{
return fac[a]*inv[b]%mod*inv[a-b]%mod;
}
long long Ca(int x1,int y1,int x2,int y2,int x3,int y3)
{
long long ret=,lx1=x3-x2-,lx2=x2-x1,ly1=y3-y2-,ly2=y2-y1;
for(int i=x1;i<=x2;i++) ret+=C(ly1+x3-i,ly1)*C(ly2-x1+i,ly2)%mod*(ly2-x1+i+)%mod,ret%=mod;
for(int i=y1;i<=y2;i++) ret+=C(lx1+y3-i,lx1)*C(lx2-y1+i,lx2)%mod*(lx2-y1+i+)%mod,ret%=mod;
return ret;
}
long long Cal(int x1,int y1,int x2,int y2)
{
long long ret=;
ret+=Ca(x1,y1,xx[],yy[],x2,y2);
ret-=Ca(x1,y1,xx[]-,yy[],x2,y2);
ret-=Ca(x1,y1,xx[],yy[]-,x2,y2);
ret+=Ca(x1,y1,xx[]-,yy[]-,x2,y2);
return (ret%mod+mod)%mod;
}
long long Calc(int x,int y)
{
long long ret=;
ret+=Cal(x,y,xx[]+,yy[]+);
ret-=Cal(x,y,xx[],yy[]+);
ret-=Cal(x,y,xx[]+,yy[]);
ret+=Cal(x,y,xx[],yy[]);
return (ret%mod+mod)%mod;
}
int main()
{
Prework();
ans+=Calc(xx[],yy[]);
ans-=Calc(xx[]-,yy[]);
ans-=Calc(xx[],yy[]-);
ans+=Calc(xx[]-,yy[]-);
printf("%lld",(ans%mod+mod)%mod);
return ;
}

2018.12.31

i207M:CF666E

广义后缀自动机+线段树合并

咕咕咕,现在还写不动,先加入字符串题单里

AubRain:Nowcoder 272D Where are you

此题出现了各种做法,下面按我认为的优秀程度升序排序

所有算法都先对边升序排序

有毒的标算:每次把一个权值的边都扔进去,对它们形成的联通块跑Tarjan,感觉非常不好写

zyz&ztb的做法:在最小生成树上差分,枚举非树边,对每个点用某个数据结构维护有哪些边被删了,最后DFS一遍统计答案

Winniechen&Suika的做法:枚举非树边,直接在最小生成树上暴力跳,跳完之后用并查集把儿子连到父亲上去,因为边权排过序了所以没问题

像我这种不会想写数据结构肯定写最后一种了2333

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
struct a
{
int x,y,val;
}mst[N];
bool cmp(a xx,a yy)
{
return xx.val<yy.val;
}
int n,m,www,cnt,ans;
int p[N],noww[*N],goal[*N],val[*N],idx[*N];
int aset[N],used[N],evl[N],eid[N],exi[N],far[N],dep[N];
int Finda(int x)
{
return x==aset[x]?x:aset[x]=Finda(aset[x]);
}
void Link(int f,int t,int v,int d)
{
noww[++cnt]=p[f],p[f]=cnt;
goal[cnt]=t,val[cnt]=v,idx[cnt]=d;
}
void DFS(int nde,int fth,int dth)
{
far[nde]=fth,dep[nde]=dth;
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=fth)
{
evl[goal[i]]=val[i];
eid[goal[i]]=idx[i];
DFS(goal[i],nde,dth+);
}
}
int main()
{
scanf("%d%d%d",&n,&m,&www),cnt=;
for(int i=;i<=m;i++)
scanf("%d%d%d",&mst[i].x,&mst[i].y,&mst[i].val);
sort(mst+,mst++m,cmp);
for(int i=;i<=n;i++) aset[i]=i;
for(int i=,j=;i<=m&&j<=n-;i++)
{
int tx=mst[i].x,ty=mst[i].y,va=mst[i].val;
int fx=Finda(tx),fy=Finda(ty);
if(fx!=fy)
{
Link(tx,ty,va,i),Link(ty,tx,va,i);
j++,used[i]=true,exi[i]=true,aset[fx]=fy;
}
}
DFS(,,);
for(int i=;i<=n;i++) aset[i]=i;
for(int i=;i<=m;i++)
if(!used[i])
{
int tx=mst[i].x,ty=mst[i].y,va=mst[i].val;
while(Finda(tx)!=Finda(ty))
{
if(dep[tx]<dep[ty]) swap(tx,ty);
if(evl[tx]==va) exi[eid[tx]]=false;
aset[Finda(tx)]=Finda(far[tx]),tx=Finda(far[tx]);
}
}
for(int i=;i<=m;i++) ans+=exi[i];
printf("%d",ans);
return ;
}

ywy_c_asm:不知道在哪看到的题

给你一个序列a:$a[1]=1,a[2n]=-a[n],a[2n-1]=-1^{n+1}a[n]$

多次询问某一项或前缀和,询问项不超过long long

直接打表找规律

看到这种每次从n推出来2*n和2*n±1的应该向二叉树上想,我们直接在二叉树上$dp$就可以了

Youngneal:LOJ 541 七曜圣贤

建议出题人重修语文,我反正没看出来魔理沙哪聪明了,那个序列的描述方法感觉更**麻烦了

另外这是什么啊↓

inline int read(int &x){scanf("%d",&x);return x;}//=。=???

不过题还不错

要求维护一个集合,支持插入/删除并丢进另一个集合/找回另一个集合里最早出现的数,每次操作之后询问集合的mex

可能一开始没什么头绪,但是有一个部分分可以带来一些启示:d=1的时候mex显然是单调的,直接模拟即可

但是我们发现因为有删除这个操作mex不是单调的,所以需要拿某个东西维护丢出去的最小的红茶和原本的mex取min做答案,还有这个数据范围明显要我们$O(n)$做......

我们发现如果有一个编号大的红茶在一个编号小的红茶之前被丢出去了,那么它会被先捡回来,不会产生贡献,所以用一个单调队列维护上面那个东西即可

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define uint unsigned int
using namespace std;
const int N=,mod=;
struct str
{
uint seed,noww,ans;
int n,a,b,c,d,tea,mex,hd1,tl1,hd2,tl2;
int p[N],out[N],inc[N],deq[N],que[N];
uint Rand()
{
seed^=seed<<;
seed^=seed>>;
seed^=seed<<;
return seed;
}
void Init()
{
scanf("%d%u%d%d%d%d",&n,&seed,&a,&b,&c,&d);
memset(inc,,sizeof inc),memset(out,,sizeof out);
for(int i=;i<=n;i++) p[i]=(Rand()%c)?Rand()%b:-;
for(int i=;i<=a;i++) inc[i]=true;
ans=,mex=a+,hd1=hd2=,tl1=tl2=-;
}
void Answer(int num)
{
ans^=1ll*num*(num+)%mod*noww%mod;
}
void Update()
{
noww=(hd1<=tl1)?min(mex,deq[hd1]):mex;
}
bool Check()
{
if(hd2<=tl2&&!d)
{
if(hd1<=tl1&&deq[hd1]==que[hd2]) hd1++;
out[que[hd2++]]=false,Update(); return true;
}
return false;
}
void Trans()
{
for(int i=;i<=n;i++)
{
tea=p[i],noww=;
if(~tea)
{
if(!inc[tea])
{
inc[tea]=true;
while(inc[mex]) mex++;
Update();
}
else if(inc[tea]&&!out[tea]&&!d)
{
out[tea]=true,que[++tl2]=tea;
while(hd1<=tl1&&tea<=deq[tl1]) tl1--;
deq[++tl1]=tea,Update();
}
else if(Check());
}
else if(Check());
Answer(i);
}
}
void Output()
{
printf("%u\n",ans);
}
}Q;
int T;
int main()
{
scanf("%d",&T);
while(T--)
Q.Init(),Q.Trans(),Q.Output();
return ;
}

2019.1.8

shadowice1984的题因为过于毒瘤并没有讲完就被打断了=。=

我的

X_stream:NOI 2008 糖果雨

(开始口胡)

看起来是个某数据结构维护函数的东西

容易想到云朵的运动以len*2为周期,以二元组$(lt,rt)$存储每一朵云,表示在(周期的)$lt$时刻这朵云到达区间的左端点,$rt$就是这朵云的长度。这样我们就将云抽象成了平面上的点。

这样画一画可以发现我们每次询问是询问一个被一个坐标轴截掉的五边形里的点数,因为是被截成五边形我们现把它补成平行四边形,然后发现边的斜率是±1,再类似切比雪夫距离转曼哈顿距离那样转成矩形,用二维树状数组维护即可

注意边界(树状数组下标不能为零,还有r==len时的特殊情况)

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,M=1e6+;
struct a
{
int lt,rt;
}cld[M];
int bit[][N][*N];
int n,t,l,r,c,d,op,mx1,mx2,len,ans;
void Change(int o,int x,int y,int z)
{
x++,y++;
for(int i=x;i<=mx1;i+=i&-i)
for(int j=y;j<=mx2;j+=j&-j)
bit[o][i][j]+=z;
}
int Query(int o,int x,int y)
{
int ret=;
x=min(x+,mx1),y=min(y+,mx2);
if(x>&&y>)
for(int i=x;i;i-=i&-i)
for(int j=y;j;j-=j&-j)
ret+=bit[o][i][j];
return ret;
}
int Ask(int o,int x1,int y1,int x2,int y2)
{
int ret=; x1--,y1--;
ret+=Query(o,x2,y2);
ret-=Query(o,x1,y2);
ret-=Query(o,x2,y1);
ret+=Query(o,x1,y1);
return ret;
}
int main()
{
scanf("%d%d",&n,&len);
mx1=len*,mx2=mx1*;
for(int i=;i<=n;i++)
{
scanf("%d",&op);
if(op==)
{
scanf("%d%d%d%d%d",&t,&c,&l,&r,&d);
int ll=(t-d*l+mx1)%mx1,rr=r-l;
cld[c].lt=ll,cld[c].rt=rr;
Change(,ll,ll+rr,),Change(,ll,rr-ll+mx1,);
}
else if(op==)
{
scanf("%d%d%d",&t,&l,&r),ans=,t%=mx1;
ans+=Ask(,t,l+t,r+t,mx2),ans+=Ask(,,l+t-mx1,r+t-mx1-(r==len),mx2);
ans+=Ask(,t-r+mx1+(r==len),l-t,mx1,mx2),ans+=Ask(,t-r,l-t+mx1,t-,mx2);
printf("%d\n",ans);
}
else if(op==)
{
scanf("%d%d",&t,&c);
int ll=cld[c].lt,rr=cld[c].rt;
Change(,ll,ll+rr,-),Change(,ll,rr-ll+mx1,-);
}
}
return ;
}

*Miracle*:PKUWC 2018 随机算法

首先转化成计数问题

设$dp[i][j]$表示$i$这个集合“被考虑过”,其独立集大小为$j$的方案数,其中“被考虑过”表示这个集合里所有的点要么在已经在独立集里要么和独立集相连。转移是记录每个点的连通性lnk,枚举没有“被考虑过”的点$k$转移

$dp[i|lnk[k]][j+1]+=dp[i][j]*P(n-siz[i]-1,siz[i-(lnk[k]\&i)])$

比较好理解的转移,其中$siz[i]$表示i集合中的点数,P是排列,因为跑不满所以$O(n^22^n)$可以卡过

更好的做法是再开一个数组记录某个状态下独立集的大小,当点数被更新时重置计数为零即可,省掉一维,复杂度$O(n2^n)$比较正确

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,S=(<<N)+N,mod=;
int lnk[N],fac[N],inv[N],dp[S],mx[S],siz[S],n,m,t1,t2,all;
void exGCD(int a,int b,int &x,int &y)
{
if(!b) x=,y=;
else exGCD(b,a%b,y,x),y-=a/b*x;
}
int Inv(int x)
{
int xx,yy;
exGCD(x,mod,xx,yy);
return (xx%mod+mod)%mod;
}
int P(int a,int b)
{
return 1ll*fac[a]*inv[a-b]%mod;
}
void Prework()
{
scanf("%d%d",&n,&m),all=(<<n)-;
for(int i=;i<=m;i++)
{
scanf("%d%d",&t1,&t2),t1--,t2--;
lnk[t1]|=<<t2,lnk[t2]|=<<t1;
}
fac[]=inv[]=;
for(int i=;i<=n;i++)
fac[i]=1ll*fac[i-]*i%mod;
inv[n]=Inv(fac[n]);
for(int i=n-;i;i--)
inv[i]=1ll*inv[i+]*(i+)%mod;
for(int i=;i<n;i++) lnk[i]|=<<i;
for(int i=;i<=all;i++)
for(int j=i;j;j-=j&-j) siz[i]++;
dp[]=;
}
int main()
{
Prework();
for(int i=;i<=all;i++)
if(dp[i])
for(int j=;j<n;j++)
if(!(i&(<<j)))
{
int news=i|lnk[j];
if(mx[news]<mx[i]+)
mx[news]=mx[i]+,dp[news]=;
if(mx[news]==mx[i]+)
dp[news]=(dp[news]+1ll*dp[i]*P(n-siz[i]-,siz[lnk[j]-(lnk[j]&i)]-)%mod)%mod;
}
printf("%lld",1ll*dp[all]*inv[n]%mod);
return ;
}

NOIWC前的交流题目汇总的更多相关文章

  1. 前端面试题目汇总摘录(JS 基础篇)

    JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string typeof null; // o ...

  2. 2016年Web前端面试题目汇总

    转载: 2016年Web前端面试题目汇总 以下是收集一些面试中经常会遇到的经典面试题以及自己面试过程中未解决的问题,通过对知识的整理以及经验的总结,重新巩固自身的前端基础知识,如有错误或更好的答案,欢 ...

  3. leetcode - 位运算题目汇总(下)

    接上文leetcode - 位运算题目汇总(上),继续来切leetcode中Bit Manipulation下的题目. Bitwise AND of Numbers Range 给出一个范围,[m, ...

  4. LeetCode 11月第2周题目汇总

    开源地址:点击该链接 前言 最近比较忙,这周几乎没有刷题,只刷了6道题~ 题目汇总 0387_first_unique_character_in_a_string类似的题目比较多了,字符串中找出特别的 ...

  5. All LeetCode Questions List 题目汇总

    All LeetCode Questions List(Part of Answers, still updating) 题目汇总及部分答案(持续更新中) Leetcode problems clas ...

  6. Python—经典练手题目汇总

    Python-经典练手题目汇总 # 1.有1020个西瓜,第一天卖掉总数的一半后又多卖出两个,以后每天卖剩下的一半多两# 个,问几天以后能卖完? day=0 xg=1020 for i in rang ...

  7. 剑指 Offer 题目汇总索引

    剑指 Offer 总目录:(共50道大题) 1. 赋值运算符函数(或应说复制拷贝函数问题) 2. 实现 Singleton 模式 (C#) 3.二维数组中的查找 4.替换空格              ...

  8. 2017年天梯赛LV2题目汇总小结

    Ⅰ.L2-021 点赞狂魔---STL应用 微博上有个"点赞"功能,你可以为你喜欢的博文点个赞表示支持.每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性 ...

  9. 2018年天梯赛LV2题目汇总小结

    Ⅰ.L2-1 分而治之---邻接表 分而治之,各个击破是兵家常用的策略之一.在战争中,我们希望首先攻下敌方的部分城市,使其剩余的城市变成孤立无援,然后再分头各个击破.为此参谋部提供了若干打击方案.本题 ...

随机推荐

  1. POJ 3164 Sunscreen (挑战程序设计竞赛的练习题)

    题目:https://vjudge.net/problem/POJ-3614 思路参考这个:https://blog.csdn.net/qq_25576697/article/details/7657 ...

  2. Codeforces70 | Codeforces Beta Round #64 | 瞎讲报告

    目录 前言 正文 A B C D E 前言 这个毒瘤的517 放了Div1 然后D题是昨天讲的动态凸包(啊喂!我还没来的及去写 结果自己想的是二分凸包 (当然没有写出来 写完前两题之后就愉快地弃疗 C ...

  3. IDA入门笔记

    题目来源: 南邮CTF :: RE :: Hello,RE(应该是) XDUCTF :: ??? :: ????????(不知道不知道不知道) 总而言之我会在百度网盘再上传一份: >>百度 ...

  4. 基于LiFi可见光通信技术的研究及应用转化调查

    这个仅是本人的部分调研结果,有同行做可见光研究的可以联系交流,QQ:391349683 

  5. java第二次试验报告

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计   班级:1353       姓名:郭皓  学号:20135327 成绩:             指导 ...

  6. JavaScript实现弹出层(以layer.open为例)

    首先,引用layer,自行下载. 添加如下两行 <script src=" ../layer/jquery.min.js"></script> <sc ...

  7. java 面试 -- 4

    Java面试知识点总结   本篇文章会对面试中常遇到的Java技术点进行全面深入的总结,帮助我们在面试中更加得心应手,不参加面试的同学也能够借此机会梳理一下自己的知识体系,进行查漏补缺(阅读本文需要有 ...

  8. Results the mutual for the first time(alpha阶段总结)

    由于前天听大家的成果展时,做得笔记不够完善,有一两个组找不到信息,如果没有评到的组望谅解. 分数分配: 由于组内某些原因,我们现重新分组: 试用版: 总结前阶段的工作: 在前一段时间,我们第一个spr ...

  9. Ubuntu 14.04(64bit)使用mentohust连接校园网

    ubuntu14.04系统安装成功之后,需要连接上网络才可以对更新系统以及安装一些必须包.而在学校中,经常遇到的情况需要通过锐捷客户端来连接校园网. 更新: 在Ubuntu14.04下面不用装ment ...

  10. java 数据结构与算法---队列

    原理来自百度百科 一.队列的定义 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表.进行插 ...