T2

考虑对于每一轮游戏,枚举有几个人选择第一个地图,剩下的人选择第二个地图,然后计算对于答案的贡献为 ,其中 表示选择第一个地图的人数, 表示选择第二个地图的人数。在每一轮取到最大值,求出总和即可。

T3

不难发现,由于给定的是 的排列,而所有数二进制只有低 位可能有 ,最大只能造出 ,所以最后排好序的排列一定满足

那么现在我们知道了目标排列,二进制的每一位就可以独立地做了。问题变为了求将一个长 序列 变成另一个 序列 ,最少需要进行多少次邻项交换。

这是经典问题,对于每个 考虑 需要交换多少次,有一个显然的下界是 即有多少个 一定要经过这里。而这个下界显然是可以取到的。

所以直接算每个 的和即可,可以使用前缀和做到线性。

那么时间复杂度为

T4

阅读条件,第 个人能将瓶子扔给:

  • 中的后缀最大值处的人;
  • 中的前缀最大值处的人;

不难发现,这些柱子形成一个类似 V 型的山谷结构,而第 个人位于谷底。故这些柱子中高度更矮的能扔向且仅能扔向高度更高的。

也就是说,求出第 个人能将瓶子扔到的人的数量 后,从第 个人开始扔瓶子相当于:

  • 每一步从 中等概率随机选择一个整数 ,令
  • 变成了 ,则停止;

这个问题的期望步数可以通过时间复杂度 的 dp 预处理:

  • 表示 时的期望步数,其中 ,则有转移:

而转移显然可以用前缀和优化到

而现在问题变成了求 ,显然可以用单调栈前后跑一次求出来。当然这也等价于笛卡尔树中 的深度,可以建笛卡尔树后 dfs 求出。

时间复杂度

T5

首先考虑单组询问 怎么做。

我们的目标是走过所有 中的点,最后再加上修建时间。刻画最优走路形态,一次传送作为一个阶段,不难发现单个阶段内只会往一个方向走,因为往回走的位置已经走过且有传送器,直接传送是不劣的。一个传送器最多被传送两次,一次向左走,一次向右走。考虑相邻两个传送器之间我必须要走到的点。有三种情况:

  1. 只使用左边的传送器,花费 次传送省去最右边不必到达的点数。
  2. 只使用右边的传送器,花费 次传送省去最左边不必到达的点数。
  3. 两边都使用,花费 次传送省去中间连续最长的不必到达的点数。

把他们合并为一种,相当于左右两端的不必到达段自动增长 ,然后只剩第三种。

考虑计数。不难发现每对相邻传送器之间相互独立,且我们只关心它们之间的距离。考虑拆贡献,设 表示相距 时中间所有方案的操作次数和。答案就是

再设 表示放了 段空位,其中最长的一段时 的方案数。处理时可以枚举 ,多记一个 表示现在有没有填恰好长 的一段,枚举一段长度填进来,前缀和优化即可。特殊处理第一段和最后一段填入时的转移即可。然后有

最后再算一下建传送门的贡献,就是 。然后处理一下边界情况即可。

T6

只有把 加, 减的操作有用。证明考虑我只关心 ,要把他变成全正,这样操作把前一个位置 后一个位置 ,不难发现其带来的贡献优于其他所有操作。

对于一次查询,考虑 形成的序列 。第一位只能用 来变大,变正后再操作它就不优了,于是我们假装第一位被删除,一直递归下去。于是我们的策略是:每次找到最前面的负数,把它 ,后面一位 。直到所有数都是正数时,我们得到答案。

考虑单点修改,记修改前 序列在操作后第 位被加了 ,那么有 。把修改看作 ,则 ,这里方便讨论,我们把上取整可能带来的 简写为 。不难发现每次 贡献除 轮后该次修改对序列的影响大概就没有了。

可是由于上取整的存在,最后可能会有一长段对序列进行 的影响。给出例子:3 3 2 5 1 3 2 5 1 3...,第一个 后面会一直产生影响。刻画这种情况发生的条件,不难发现条件是 奇偶相间。线段树维护奇偶相同的位置,线段树二分找到终止点,支持区间奇偶翻转,暴力下放标记。

做到

偷懒写分块可能也能过。

Code

T2

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int a[110][10010];
int n,m;
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>a[i][j];
	int res=0;
	for(int i=1;i<=m;i++){
		int x=0,y=0,mx=0;
		for(int j=1;j<=n;j++)x+=(a[j][i]==0),y+=(a[j][i]==1);
		for(int i=x;n-i>=y;i++){
			int a=i,b=n-i;
			mx=max(mx,a*(b+1)+(a+1)*b);
		}
		res+=mx;
	}
	cout<<res<<endl;
}

T3

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long ll;

const int S=2000005;

inline int mabs(int x){return x<0?-x:x;}

int n,m,a[S],b[S];
int c[S],d[S];

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n;
	m=1<<n;
	for(int i=1;i<=m;i++) cin>>a[i];
	for(int i=1;i<=m;i++) b[i]=i-1;
	ll ans=0;
	for(int i=0;i<n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			c[j]=a[j]>>i&1;
			d[j]=b[j]>>i&1;
		}
		int x=0;
		for(int j=1;j<=m;j++)
		{
			x+=c[j]-d[j];
			ans+=mabs(x);
		}
	}
	cout<<ans<<'\n';
	return 0;
}

T4

#include <iostream>
#include <cstdio>

using namespace std;

#define p 1000000007

inline void add(int &x,int y)
{
	x+=y;
	if(x>=p) x-=p;
}
inline int qpow(int x,int y)
{
	int res=1;
	for(;y>0;y>>=1,x=1ll*x*x%p) res=y&1?1ll*res*x%p:res;
	return res;
}

const int S=1000005;

int fra[S],inv[S];
int n,a[S],pos[S];
int top,sta[S];
int fat[S],dep[S];
int f[S];

int main()
{
	fra[0]=1;
	for(int i=1;i<=S-3;i++) fra[i]=1ll*fra[i-1]*i%p;
	inv[S-3]=qpow(fra[S-3],p-2);
	for(int i=S-3;i>=1;i--) inv[i-1]=1ll*inv[i]*i%p;
	for(int i=1;i<=S-3;i++) inv[i]=1ll*inv[i]*fra[i-1]%p;
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],pos[a[i]]=i;
	for(int i=1;i<=n;i++)
	{
		bool fl=false;
		while(top>0&&a[sta[top]]<a[i]) top--,fl=true;
		if(fl) fat[sta[top+1]]=i;
		fat[i]=sta[top];
		sta[++top]=i;
	}
	dep[0]=-1;
	for(int i=n;i>=1;i--)
	{
		int u=pos[i];
		dep[u]=dep[fat[u]]+1;
	}
	f[0]=0;
	for(int i=1,sm=0;i<=n;i++)
	{
		f[i]=(1ll*sm*inv[i]%p+1)%p;
		add(sm,f[i]);
	}
	for(int i=1;i<=n;i++) cout<<f[dep[i]]<<' ';
	cout<<'\n';
	return 0;
}

T5

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,mod,g[5001][5001][2],gsum[5001][5001],f[5001][2],pw3[5001],pw2[5001],GONX1,GONX0,FINW,JIEW;
int MOD(int x)
{
	return (x>=mod?x-mod:x);
}
signed main()
{
	ios::sync_with_stdio(false);
	cin>>n>>mod;
	pw3[0]=pw2[0]=1;
	pw3[1]=3,pw2[1]=2;
	for(int i=2;i<=n;i++)
	{
		pw3[i]=pw3[i-1]*3%mod;
		pw2[i]=pw2[i-1]*2%mod;
		g[1][i][0]=1;
		gsum[1][i]=1;
		for(int z=2;z<=n;z++)
		{
			int far=z-i;
			if(far<0) g[z][i][0]=gsum[z-1][i];
			else g[z][i][0]=MOD(gsum[z-1][i]-gsum[far][i]+mod);
			gsum[z][i]=MOD(gsum[z-1][i]+g[z][i][0]);
			far++;
			if(far<0) g[z][i][1]=gsum[z-1][i];
			else g[z][i][1]=MOD(gsum[z-1][i]-gsum[far][i]+mod);
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int z=2;z<i;z++)
		{
			(f[i][0]+=(g[i][z][0]-g[i][z-1][0]+mod)*(2+(i-1)-(z-1)))%=mod;
			f[i][0]=MOD(f[i][0]-g[i-z+1][z][0]+mod);
			f[i][0]=MOD(f[i][0]-g[i-z+1][z][1]+mod);
			(f[i][1]+=(g[i][z][0]-g[i][z-1][0]+mod)*(1+(i-1)-(z-1)))%=mod;
			f[i][1]=MOD(f[i][1]-g[i-z+1][z][0]+mod);
		}
		(ans+=pw3[n-i]*f[i][0]%mod*(n-i))%=mod;
		(ans+=pw3[n-i+1]*f[i][1])%=mod;
		ans=MOD(ans+pw3[n-1]);
		ans=(ans+pw3[n-i]*(i-(i==n))%mod*pw2[i-1])%mod;
	}
	cout<<MOD(ans+(n-1)*pw2[n]%mod);
}

T6

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#include<cassert>
#define int long long
#define LAG 80
#define INF 1000000000
using namespace std;
int n,m,rans,b[1000001],a[1000001],num[1000001],ma;
int chng[4000001];
namespace SEG
{
	int sam[4000001],rev[4000001];
	void dwntg(int o,int l,int r)
	{
		rev[o<<1]^=rev[o];
		rev[o<<1|1]^=rev[o];
		rev[o]=0;
		if(l+1==r)
		{
			if(rev[o<<1]) chng[l]=-chng[l];
			rev[o<<1]=0;
			if(rev[o<<1|1]) chng[r]=-chng[r];
			rev[o<<1|1]=0;
		}
	}
	void add(int o,int l,int r,int x,int y)
	{
		if(x>y) return;
		if(x<=l&&r<=y)
		{
			rev[o]^=1;
			return;
		}
		dwntg(o,l,r);
		int mid=l+r>>1;
		if(x<=mid) add(o<<1,l,mid,x,y);
		if(y>mid) add(o<<1|1,mid+1,r,x,y);
	}
	void dwntg(int o,int l,int r,int x,int y)
	{
		if(l==r)
		{
			if(rev[o]) chng[l]=-chng[l];
			rev[o]=0;
			return;
		}
		dwntg(o,l,r);
		int mid=l+r>>1;
		if(x<=mid) dwntg(o<<1,l,mid,x,y);
		if(y>mid) dwntg(o<<1|1,mid+1,r,x,y);
	}
	void build(int o,int l,int r,int x,int y)
	{
		if(x>y) return;
		if(l==r)
		{
			if(chng[l]==chng[l-1]||chng[l]==0) sam[o]=1;
			else sam[o]=0;
			return;
		}
		dwntg(o,l,r);
		int mid=l+r>>1;
		if(x<=mid) build(o<<1,l,mid,x,y);
		if(y>mid) build(o<<1|1,mid+1,r,x,y);
		sam[o]=(sam[o<<1]|sam[o<<1|1]);
	}
	int find(int o,int l,int r,int x)
	{
		if(l==r)
		{
			if(sam[o]) return l-1;
			return l;
		}
		dwntg(o,l,r);
		int mid=l+r>>1;
		if(x>mid) return find(o<<1|1,mid+1,r,x);
		if(x>=l)
		{
			int w=find(o<<1,l,mid,x);
			if(w==mid) return find(o<<1|1,mid+1,r,x);
			return w;
		}
		if(sam[o<<1]) return find(o<<1,l,mid,x);
		return find(o<<1|1,mid+1,r,x);
	}
}
using namespace SEG;
int gocal()
{
	for(int i=1;i<=n;i++) b[i]=a[i];
	for(int i=2;i<=n;i+=2)
	{
		if(b[i-1]<=b[i])
		{
			if((b[i]-b[i-1])%2) chng[i/2]=1;
			else chng[i/2]=-1;
			num[i]=(b[i]-b[i-1])/2;
			int rnum=num[i]+(chng[i/2]==1);
			b[i-1]+=rnum;
			b[i]-=rnum;
			b[i+1]+=rnum;
			rans+=rnum;
		}
	}
	return rans;
}
void gans()
{
	cout<<gocal()<<"\n";
}
void flush(int w,int id)
{
	int pr=w+w%2,delta=0;
	dwntg(1,1,n/2,max(1ll,pr/2-1),min(n/2,(pr+LAG)/2+1));
	for(int i=pr;i<=min(n,pr+LAG);i+=2)
	{
		b[i-1]=a[i-1];
		b[i]=a[i];
		int rnum=num[i-2]+(chng[(i-2)/2]==1);
		b[i-1]+=rnum;
		rans-=num[i]+(chng[i/2]==1);
		delta=-(num[i]+(chng[i/2]==1));
		if(b[i-1]<=b[i])
		{
			if((b[i]-b[i-1])%2) chng[i/2]=1;
			else chng[i/2]=-1;
			num[i]=(b[i]-b[i-1])/2;
			int rnum=num[i]+(chng[i/2]==1);
			b[i-1]+=rnum;
			b[i]-=rnum;
			rans+=rnum;
			delta+=rnum;
		}
		else
		{
			chng[i/2]=0;
			num[i]=0;
		}
	}
	build(1,1,n/2,max(1ll,pr/2),min(n/2,(pr+LAG)/2));
	if(delta!=0&&(pr+LAG)<=n)
	{
		int wc=find(1,1,n/2,(pr+LAG)/2);
		add(1,1,n/2,(pr+LAG)/2+1,wc);
		if(wc+1<=n/2)
		{
			dwntg(1,1,n/2,wc,wc+2);
			int rnum=num[wc+wc]+(chng[wc]==1);
			b[wc+wc+1]=a[wc+wc+1];
			b[wc+wc+2]=a[wc+wc+2];
			b[wc+wc+1]+=rnum;
			if(b[wc+wc+1]<=b[wc+wc+2])
			{
				if((b[wc+wc+2]-b[wc+wc+1])%2) chng[wc+1]=1;
				else chng[wc+1]=-1;
				num[wc+wc+2]=(b[wc+wc+2]-b[wc+wc+1])/2;
			}
			else
			{
				chng[wc+1]=0;
				num[wc+wc+2]=0;
			}
			build(1,1,n/2,wc+1,wc+2);
		}
		rans+=-delta*((wc-(pr+LAG)/2)%2);
	}
	cout<<rans<<"\n";
}
signed main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    n=n+n+1;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
	}
	gans();
	build(1,1,n/2,1,n/2);
	for(int i=1,w,v;i<=m;i++)
	{
		cin>>w>>v;
		a[w]=v;
		flush(w,i);
	}
}