A

差分即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<queue>
#include<stack>
#include<bitset>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='0')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
const int N=1e5+10;
ll b1[N],b[N],d[N];
//b1:操作 b:数组
int l[N],r[N],a[N];
int main()
{
	int n=read(),m=read(),k=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=m;i++)l[i]=read(),r[i]=read(),d[i]=read();
	for(int i=1;i<=k;i++){int x=read(),y=read();b1[x]++,b1[y+1]--;}
	for(int i=1;i<=m;i++)b1[i]+=b1[i-1];
	for(int i=1;i<=m;i++)
	{
		d[i]=d[i]*b1[i];
		b[l[i]]+=d[i],b[r[i]+1]-=d[i];
	}
	for(int i=1;i<=n;i++)b[i]+=b[i-1];
	for(int i=1;i<=n;i++)printf("%lld ",b[i]+a[i]);
	return 0;
}

B

考虑Floyd的过程,相当于是每次加一个点然后考虑对全图的影响,和给定操作倒着来是等价的。\(\mathcal O(n^3)\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<queue>
#include<stack>
#include<bitset>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define int long long
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='0')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
const int N=510;
int e1[N][N],Ans[N],e[N][N];
int x[N];bool vis[N];
signed main()
{
	int n=read();
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)e[i][j]=read();
	for(int i=1;i<=n;i++)x[i]=read();
	for(int k=n;k;k--)
	{
		vis[x[k]]=1;
		for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)e[i][j]=min(e[i][j],e[i][x[k]]+e[x[k]][j]);
		for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(vis[i]&&vis[j])Ans[k]+=e[i][j];
	}
	for(int i=1;i<=n;i++)printf("%lld ",Ans[i]);
	return 0;
}

C

以前写的题解

下文中大写 \(K\) 表示输入的变量,小写 \(k\) 表示枚举的变量。

假设有 \(tot_5\)\(50\mathrm{kg}\) 的人,\(tot_1\)\(100\mathrm{kg}\) 的人,\(f(pos,j,k)\) 表示这一轮结束后船在 \(pos\) 岸(\(0\) 为出发岸,\(1\) 为对岸),对岸 \(50\mathrm{kg}\) 的有 \(j\) 个,\(100\mathrm{kg}\) 的有 \(k\) 个,方案数是多少。那么有两种情况:

I. \(pos=0\)

\[f(1,j+c_5,k+c_1)\gets f(1,j+c_5,k+c_1)+\binom{tot_5-j}{c_t}\binom{tot_1-k}{c_1}f(0,j,k) \]

其中 \(c_5,c_1\) 是枚举的变量,满足 \(0\le c_5\le tot_5-j\)\(0\le c_1\le tot_1-k\)\(0< 50c_5+100c_1\le K\)

II. \(pos=1\)

\[f(0,j-c_5,k-c_1)\gets f(0,j-c_5,k-c_1)+\binom{j}{c_5}\binom{k}{c_1}f(1,j,k) \]

同理,\(0\le c_5\le j\)\(0\le c_1\le k\)\(0<50c_5+100c_1\le K\)

初始值为 \(f(0,0,0)=1\),其余为 \(0\)。枚举轮数(一来一回算两轮)\(i\)\(i\) 对应的 \(pos\) 就是 \(i\bmod 2\)。当 \(f(i\bmod 2,n,n)\not= 0\;(i\bmod 2=1)\) 时则最小值为 \(i\)。如果 \(i>4n\) 时还没有答案,那么一定无解。

#include<bits/stdc++.h>
using namespace std;
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^48);c=getchar();}
	return x*f;
}
const int mod=1e9+7,N=310;
inline int qpow(int a,int n)
{
	int ans=1;
	while(n)
	{
		if(n&1)ans=(long long)ans*a%mod;
		a=(long long)a*a%mod;
		n>>=1;
	}
	return ans;
}
int inv[N],p[N];
int binom(int n,int m){return (long long)p[n]*inv[n-m]%mod*inv[m]%mod;}
int f[2][60][60];
int main()
{
	p[0]=inv[0]=1;
	for(int i=1;i<=50;i++)p[i]=(long long)p[i-1]*i%mod,inv[i]=qpow(p[i],mod-2);
	int n=read(),K=read(),tot5=0,tot1=0;
	for(int i=1;i<=n;i++)
	{
		int x=read();
		tot5+=(x==50);
		tot1+=(x==100);
	}
	f[0][0][0]=1;
	for(int i=1;i<=4*n;i++)
	{
		for(int j=0;j<=tot5;j++)
			for(int k=0;k<=tot1;k++)
				f[i&1][j][k]=0;
		for(int j=0;j<=tot5;j++)
		{
			for(int k=0;k<=tot1;k++)
			{
				if(i&1)
				{
					for(int c5=0;c5<=tot5-j;c5++)
					{
						for(int c1=0;c1<=tot1-k;c1++)
						{
							if(!c5&&!c1)continue;
							if(50*c5+100*c1>K) continue;
							f[1][j+c5][k+c1]+=(long long)binom(tot5-j,c5)*binom(tot1-k,c1)%mod*f[0][j][k]%mod;
							f[1][j+c5][k+c1]%=mod;
						}
					}
				}
				else
				{
					for(int c5=0;c5<=j;c5++)
					{
						for(int c1=0;c1<=k;c1++)
						{
							if(!c5&&!c1)continue;
							if(50*c5+100*c1>K) continue;
							f[0][j-c5][k-c1]+=(long long)binom(j,c5)*binom(k,c1)%mod*f[1][j][k]%mod;
							f[0][j-c5][k-c1]%=mod;
						}
					}
				}
			}
		}
		if(f[i&1][tot5][tot1])
		{
			printf("%d\n%d",i,f[i&1][tot5][tot1]);
			return 0;
		}
	}
	printf("-1\n0");
	return 0;
}

D

枚举最长的那一行以及这一行的黑点个数,钦定上面的行的行黑色点构成的集合都是这一行的真子集,下面的是子集。上面和下面的方案 dp 求出之后相乘再乘一个可以安排的位置数量就是他的贡献。下面的 dp 就是 \(f(i,j)\) 表示这一行是长度为 \(i\) 的,加上这一行总共摆了 \(j\) 行,通过前缀和优化可以做到 \(\mathcal O(n^2)\),上面同理。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<queue>
#include<stack>
#include<bitset>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='0')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
const int N=2010,mod=1e9+7;
int f[N][N],sum1[N][N],sum2[N][N],ff[N][N];
//sum1: sigma_k f(k,j-1),   sum2:sigma_k (k-1)f(k,j-1)
int Sum1[N][N],Sum2[N][N];
//Sum1: sigma_j f(i,j)  Sum2: sigma_j ff(i,j)
int main()
{
	int n=read(),m=read();
	for(int i=2;i<=m;i++)f[i][1]=1,sum1[i][1]=(sum1[i-1][1]+f[i][1])%mod,sum2[i][1]=(sum2[i-1][1]+f[i][1]*1ll*(i-1)%mod)%mod;
	for(int j=2;j<=n;j++)
	{
		for(int i=2;i<=m;i++)
		{
			f[i][j]=(1ll*i*sum1[i][j-1]%mod-sum2[i][j-1]+mod)%mod;
			sum1[i][j]=(sum1[i-1][j]+f[i][j])%mod;
			sum2[i][j]=(sum2[i-1][j]+1ll*f[i][j]*(i-1)%mod)%mod;
		}
	}
	for(int i=1;i<=m;i++)ff[i][1]=1;
	for(int j=2;j<=n;j++)
		for(int i=1;i<=m;i++)
			ff[i][j]=(1ll*i*sum1[i-1][j-1]%mod-sum2[i-1][j-1]+mod)%mod;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)Sum1[i][j]=(Sum1[i][j-1]+f[i][j])%mod;
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)Sum2[i][j]=(Sum2[i][j-1]+ff[i][j])%mod;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=2;j<=m;j++)
			ans+=1ll*(m-j+1)*Sum1[j][i]%mod*Sum2[j][n-i+1]%mod,ans%=mod;
	}
	printf("%d",ans);
}

E

权值线段树维护 \(cnt,sum,ans\),即这一段的点数量,这一段点的坐标和,这一段的答案,询问直接向上合并即可。具体来说就是:

struct node
{
	int cnt,sum,ans;
	node(){cnt=sum=ans=0;}
	node(int c,int s,int a){cnt=c,sum=s,ans=a;}
	node operator+(const node &x)const 
	{
		node Ans;
		Ans.ans=ans+x.ans;
		Ans.cnt=cnt+x.cnt;
		Ans.sum=sum+x.sum;
		Ans.ans+=x.sum*cnt;
		Ans.ans-=sum*x.cnt;
		return Ans;
	}
};

\(\mathcal O(n\log n)\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<queue>
#include<stack>
#include<bitset>
#include<vector>
#include<map>
#include<set>
#define int long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
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^48);c=getchar();}
	return x*f;
}
const int N=1e6+10;
int tmp[N],x[N],xx[N];
pair<int,pii> q[N];
struct node
{
	int cnt,sum,ans;
	node(){cnt=sum=ans=0;}
	node(int c,int s,int a){cnt=c,sum=s,ans=a;}
	node operator+(const node &x)const 
	{
		node Ans;
		Ans.ans=ans+x.ans;
		Ans.cnt=cnt+x.cnt;
		Ans.sum=sum+x.sum;
		Ans.ans+=x.sum*cnt;
		Ans.ans-=sum*x.cnt;
		return Ans;
	}
};
struct sgt
{
	struct seg
	{
		int l,r,cnt,sum,ans;
		seg(){l=r=cnt=sum=ans=0;}
	}t[N<<2];
	void build(int p,int l,int r)
	{
		t[p].l=l,t[p].r=r;
		if(l==r) return;
		int mid=(l+r)>>1;
		build(p*2,l,mid);
		build(p*2+1,mid+1,r);
	}
	void pu(int p)
	{
		t[p].sum=t[p*2].sum+t[p*2+1].sum;
		t[p].cnt=t[p*2].cnt+t[p*2+1].cnt;
		t[p].ans=t[p*2].ans+t[p*2+1].ans;
		t[p].ans+=t[p*2+1].sum*t[p*2].cnt;
		t[p].ans-=t[p*2].sum*t[p*2+1].cnt;
	}
	void modify(int p,int x,int d)
	{
		if(t[p].l==t[p].r)
		{
			t[p].cnt+=d;
			t[p].ans=0;
			t[p].sum+=d*tmp[x];
			return;
		}
		int mid=(t[p].l+t[p].r)>>1;
		if(x<=mid)modify(p*2,x,d);
		else modify(p*2+1,x,d);
		pu(p);
	}
	node query(int p,int l,int r)
	{//cnt, sum, ans
		if(l<=t[p].l&&t[p].r<=r)return node(t[p].cnt,t[p].sum,t[p].ans);
		int mid=(t[p].l+t[p].r)>>1;
		node ans;
		if(l<=mid)ans=ans+query(p*2,l,r);
		if(r>mid)ans=ans+query(p*2+1,l,r);
		return ans;
	}
}T;
signed main()
{

	int n=read(),c=0;
	for(int i=1;i<=n;i++)xx[i]=x[i]=read(),tmp[++c]=x[i];
	int m=read();
	for(int i=1;i<=m;i++)
	{
		int p=read();
		if(p==1){int p=read(),d=read();xx[p]+=d,tmp[++c]=xx[p];q[i]=mp(1,mp(p,d));}
		else {int l=read(),r=read();q[i]=mp(2,mp(l,r)),tmp[++c]=l,tmp[++c]=r;}
	}
	sort(tmp+1,tmp+c+1);c=unique(tmp+1,tmp+c+1)-tmp-1;
	T.build(1,1,c);	
	for(int i=1;i<=m;i++)
	{
		if(q[i].fi==2)
		{
			q[i].se.fi=lower_bound(tmp+1,tmp+c+1,q[i].se.fi)-tmp;
			q[i].se.se=lower_bound(tmp+1,tmp+c+1,q[i].se.se)-tmp;
		}
	}
	for(int i=1;i<=n;i++)
	{
		int z=lower_bound(tmp+1,tmp+c+1,x[i])-tmp;
		T.modify(1,z,1);
	}
	for(int i=1;i<=m;i++)
	{
		int pos=q[i].fi;
		if(pos==1)	
		{
			int p=q[i].se.fi,d=q[i].se.se;
			int z=lower_bound(tmp+1,tmp+c+1,x[p])-tmp;
			T.modify(1,z,-1);
			x[p]+=d;
			z=lower_bound(tmp+1,tmp+c+1,x[p])-tmp;
			T.modify(1,z,1);
		}
		else
		{
			int l=q[i].se.fi,r=q[i].se.se;
			node x=T.query(1,l,r);
			printf("%lld\n",x.ans);
		}
	}
	return 0;
}