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\):
其中 \(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\):
同理,\(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;
}