2023.9.23
A
给出序列 \(\{a\}\),问有多少非空子集满足平均数 \(<\) 中位数。
\(n\le 100\),\(a_i\le 800\).
可以 \(O(n^3V)\) 直接 DP。大家写的反悔背包常数很小。
#include<bits/stdc++.h>
#define ll long long
#define N 105
#define V 805
#define P 998244353
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
int read(){
int x=0,w=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*w;
}
int n,v,a[N],s;
int f[N>>1][N*V],g[N>>1][N*V][2],sum[N>>1][N*V],ans;
void prework(){
s=n*v;
f[0][0]=g[0][0][0]=1;
for(int i=1;i<=n;i++)
for(int j=n/2;j;j--)
for(int k=s;k>=a[i];k--)
(g[j][k][0]+=g[j-1][k-a[i]][0])%=P;
}
void solve1(int i){
if(!i)return;
for(int j=n/2;j;j--)
for(int k=s;k>=a[i];k--)
(f[j][k]+=f[j-1][k-a[i]])%=P;
}
void solve2(int i){
g[0][0][1]=1;
for(int j=1;j<=n/2;j++)
for(int k=0;k<=s;k++){
if(k<a[i])g[j][k][1]=g[j][k][0];
else g[j][k][1]=(g[j][k][0]-g[j-1][k-a[i]][1]+P)%P;
g[j][k][0]=g[j][k][1];
sum[j][k]=(sum[j][k-1]+g[j][k][0])%P;
}
}
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
n=read(),v=read();
for(int i=1;i<=n;i++)a[i]=read();
sort(a+1,a+1+n);
prework();
for(int i=1;i<=n;i++){
solve1(i-1),solve2(i);
for(int j=1;j<=min(i-1,n-i);j++)
for(int k=1,S=j*2*a[i];k<S;k++)
(ans+=1ll*f[j][k]*sum[j][S-k-1]%P)%=P;
}
printf("%d\n",ans);
return 0;
}
B
P8906 [USACO22DEC] Breakdown P
一个有向完全图(包括自环),进行 \(n^2\) 次删边,问每次删边后从 \(1\) 到 \(n\) 的长为 \(k\) 的最短路长度,或指出不存在长为 \(k\) 的 \(1\) 到 \(n\) 的路径。
\(n\le 300\),\(2\le k\le 8\),\(1\le w_{i,j}\le 10^8\).
容易想到分层图,直接跑是 \(O(n^4k)\) 的。
考虑折半,对于所有点,记录从 \(1\) 开始经过 \(\lfloor\frac{k}{2}\rfloor\) 条边到达它,和从它开始经过 \(\lceil\frac{k}{2}\rceil\) 条边到达 \(n\) 的最短路。
先化删为加。添加一条边时,依次扫过分层图的每一层,若一个点被松弛过,将其所有出边松弛一遍。
时间复杂度 \(O(n^4k)\) 小常数不好卡。
#include<bits/stdc++.h>
#define ll long long
#define N 305
#define inf 1e12
using namespace std;
int read(){
int x=0,w=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*w;
}
int n,k,_w[N][N];
int w[N][N],ans[N*N];
int X[N*N],Y[N*N];
struct Graph{
int d[N][5];bool vs[N][5];
int st,k;
void init(int x,int p){
memset(d,0x3f,sizeof(d));
d[x][0]=0,st=x,k=p;
}
void upd(int x){
memset(vs,0,sizeof(vs));
for(int i=0;i<k;i++)vs[x][i]=1;
for(int i=0;i<k;i++)
for(int u=1;u<=n;u++)
if(vs[u][i]){
for(int v=1;v<=n;v++){
if(d[v][i+1]>d[u][i]+w[u][v])
vs[v][i+1]=true,d[v][i+1]=d[u][i]+w[u][v];
}
}
}
}p1;
struct Graph2{
int d[N][5];bool vs[N][5];
int st,k;
void init(int x,int p){
memset(d,0x3f,sizeof(d));
d[x][0]=0,st=x,k=p;
}
void upd(int x){
memset(vs,0,sizeof(vs));
for(int i=0;i<k;i++)vs[x][i]=true;
for(int i=0;i<k;i++)
for(int u=1;u<=n;u++)
if(vs[u][i]){
for(int v=1;v<=n;v++){
if(d[v][i+1]>d[u][i]+w[v][u])
vs[v][i+1]=true,d[v][i+1]=d[u][i]+w[v][u];
}
}
}
}p2;
int main(){
n=read(),k=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
_w[i][j]=read(),w[i][j]=1e9;
for(int i=1;i<=n*n;i++)
X[i]=read(),Y[i]=read();
p1.init(1,k>>1),p2.init(n,k+1>>1);
for(int i=n*n;i;i--){
ans[i]=2e9;
for(int j=1;j<=n;j++)
ans[i]=min(ans[i],p1.d[j][k>>1]+p2.d[j][k+1>>1]);
if(ans[i]>=1e9)ans[i]=-1;
w[X[i]][Y[i]]=_w[X[i]][Y[i]];
p1.upd(X[i]),p2.upd(Y[i]);
}
for(int i=1;i<=n*n;i++)
printf("%d\n",ans[i]);
return 0;
}
C
构造一个单调不升的非负数列 \(\{b\}\),最小化
\[\sum_{i=1}^{n}f(b_i,a_i)
\]
其中
\[f(x,y)=\begin{cases}x-y&x\ge y\\C&x<y\end{cases}
\]
\(n\le 10^6\),\(0\le V\le 10^9\).
比较难的一集。没太贺懂。
#include<bits/stdc++.h>
#define ll long long
#define N 2000010
using namespace std;
int read(){
int x=0,w=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*w;
}
int n,a[N],b[N],id[N];
ll dat[N<<2],tag1[N<<2],tag2[N<<2],C;
bool fl[N<<2];
#define ls p<<1
#define rs p<<1|1
void pushfl(int p){
if(!fl[p])return;
dat[ls]=dat[rs]=dat[p];
tag1[ls]=tag1[rs]=tag2[ls]=tag2[rs]=0;
fl[ls]=fl[rs]=1,fl[p]=0;
}
void pushdown(int p,int mid,int r){
pushfl(p);
pushfl(ls),pushfl(rs);
if(tag1[p]){
dat[ls]+=tag1[p],tag1[ls]+=tag1[p];
dat[rs]+=tag1[p],tag1[rs]+=tag1[p];
tag1[p]=0;
}
if(tag2[p]){
dat[ls]+=b[mid]*tag2[p],tag2[ls]+=tag2[p];
dat[rs]+=b[r]*tag2[p],tag2[rs]+=tag2[p];
tag2[p]=0;
}
}
void pushup(int p){
dat[p]=min(dat[ls],dat[rs]);
}
ll val;
void update(int p,int l,int r,int x,ll v1,ll v2){
int mid=(l+r)>>1;
if(l!=r)pushdown(p,mid,r);
if(r<=x){
pushfl(p);
dat[p]+=v1,tag1[p]+=v1;
dat[p]+=b[r],tag2[p]++;
if(r==x)val=dat[p];
return;
}
if(l>x){
pushfl(p);
dat[p]+=v2,tag1[p]+=v2;
return;
}
update(ls,l,mid,x,v1,v2);
update(rs,mid+1,r,x,v1,v2);
pushup(p);
}
bool modify(int p,int l,int r,int x,ll v){
int mid=(l+r)>>1;
if(l!=r)pushdown(p,mid,r);
if(l>x){
if(dat[p]>v){
dat[p]=v,tag1[p]=tag2[p]=0;
fl[p]=1;
return 1;
}
if(l!=r){
if(modify(ls,l,mid,x,v))
modify(rs,mid+1,r,x,v);
}
return 0;
}
if(l==r)return 0;
if(x<mid){
if(modify(ls,l,mid,x,v))
return modify(rs,mid+1,r,x,v);
return 0;
}
return modify(rs,mid+1,r,x,v);
}
int main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
n=read(),C=read();
for(int i=1;i<=n;i++)
a[i]=b[i]=read();
sort(b+1,b+1+n);
int len=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++){
id[i]=lower_bound(b+1,b+1+len,a[i])-b;
id[i]=len-id[i]+1;
}
reverse(b+1,b+1+len);
for(int i=1;i<=n;i++){
update(1,1,len,id[i],-a[i],C);
modify(1,1,len,id[i],val);
}
printf("%lld\n",dat[1]);
return 0;
}