2023.9.23测试
T1 雷老师的正偏态分布
给出一组数据
容易想到排序,然后枚举中位数
因为值域很小,可以左右两边背包,设
其实发现对于左边来说,每次移动相当于加上一个数,对于右边来说相当于减去一个数(即反悔背包),这样可以做到
code
#include<bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define LL long long
using namespace std;
const int N=110,V=810;
const int MOD=998244353;
int n,v,a[N],t,s;
int f[N>>1][N*V],g[N>>1][N*V][2],sum[N>>1][N*V],ans;
void prework()
{
t=n/2; s=n*v;
f[0][0]=g[0][0][0]=1;
for(int i=1; i<=n; i++)
for(int j=t; j>=1; j--)
for(int k=s; k>=0; k--)
(g[j][k][0]+=g[j-1][k-a[i]][0])%=MOD;
}
void solve1(int i)
{
if(i<1)
return;
for(int j=t; j>=1; j--)
for(int k=s; k>=a[i]; k--)
(f[j][k]+=f[j-1][k-a[i]])%=MOD;
}
void solve2(int i)
{
if(i<1)
return;
g[0][0][1]=1;
for(int j=1; j<=t; 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])%MOD+MOD)%MOD;
g[j][k][0]=g[j][k][1];
sum[j][k]=(sum[j][k-1]+g[j][k][0])%MOD;
}
}
}
int main()
{
// freopen("end010.in","r",stdin);
// freopen("a.out","w",stdout);
scanf("%d%d",&n,&v);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
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]%MOD)%=MOD;
}
printf("%d",ans);
return 0;
}
T2 假期计划Ⅱ
(P8906 [USACO22DEC] Breakdown P)
有点像 CSP-2022 T1 加强版
首先删边转加边,经典套路
之后也是经典的折半搜,设
考虑维护任意两点间最短路
注意特判
code
#include<bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
const int N=310,M=90010,INF=1e9;
int n,k,m,ans[M];
int e[N][N],u[M],v[M];
struct GR
{
int k,st,e[N][N],f[N][N],h[N];
void init(int _k,int _st)
{
k=_k; st=_st;
memset(e,0x3f,sizeof(e));
memset(f,0x3f,sizeof(f));
memset(h,0x3f,sizeof(h));
if(!k)
h[st]=0;
}
void add(int x,int y,int z)
{
e[x][y]=z;
if(!k)
return;
if(k==1)
{
if(x==st)
h[y]=z;
return;
}
for(int i=1; i<=n; i++)
{
f[i][y]=min(f[i][y],e[i][x]+z);
f[x][i]=min(f[x][i],z+e[y][i]);
}
if(k==2)
{
for(int i=1; i<=n; i++)
h[i]=f[st][i];
return;
}
auto p=(k==3)? e:f;
if(x==st)
{
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
h[j]=min(h[j],f[x][i]+p[i][j]);
}
for(int i=1; i<=n; i++)
{
h[i]=min(h[i],f[st][x]+p[x][i]);
h[i]=min(h[i],f[st][y]+p[y][i]);
h[x]=min(h[x],f[st][i]+p[i][x]);
h[y]=min(h[y],f[st][i]+p[i][y]);
}
}
}k1,k2;
int main()
{
memset(ans,0x3f,sizeof(ans));
scanf("%d%d",&n,&k);
m=n*n;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
scanf("%d",&e[i][j]);
for(int i=1; i<=m; i++)
scanf("%d%d",&u[i],&v[i]);
int lcnt=k/2,rcnt=k-lcnt;
k1.init(lcnt,1); k2.init(rcnt,n);
for(int i=m; i>=1; i--)
{
for(int j=1; j<=n; j++)
ans[i]=min(ans[i],k1.h[j]+k2.h[j]);
k1.add(u[i],v[i],e[u[i]][v[i]]);
k2.add(v[i],u[i],e[u[i]][v[i]]);
}
for(int i=1; i<=m; i++)
{
if(ans[i]>=INF)
printf("-1\n");
else
printf("%d\n",ans[i]);
}
return 0;
}
T3 永不加班
很蓝的啦
考虑朴素的 DP,设
对
因此,操作时只需线段树二分出
仔细思考一下可以得知
-
区间加法
-
区间赋值
-
线段树二分出
的位置最后一个 的位置 ,保证 的位置具有单调性
线段树维护即可
code
#include<bits/stdc++.h>
#define LL long long
#define lc(p) p<<1
#define rc(p) p<<1|1
using namespace std;
const int N=1e6+10;
int n,m,C;
int a[N],b[N];
struct Seg
{
LL dat,fu,ad1,ad2;
#define dat(x) tree[x].dat
#define fu(x) tree[x].fu
#define ad1(x) tree[x].ad1
#define ad2(x) tree[x].ad2
void add(LL v1,LL v2,int l)
{
dat+=v1+1LL*v2*b[l];
ad1+=v1; ad2+=v2;
}
void cov(LL v)
{
dat=fu=v;
ad1=ad2=0;
}
}tree[N<<2];
void pushup(int p)
{
dat(p)=max(dat(lc(p)),dat(rc(p)));
}
void spread(int p,int l,int r)
{
int mid=(l+r)>>1;
if(fu(p)!=-1)
{
tree[lc(p)].cov(fu(p));
tree[rc(p)].cov(fu(p));
fu(p)=-1;
}
if(ad1(p) || ad2(p))
{
tree[lc(p)].add(ad1(p),ad2(p),mid);
tree[rc(p)].add(ad1(p),ad2(p),r);
ad1(p)=ad2(p)=0;
}
}
void build(int p,int l,int r)
{
fu(p)=-1;
dat(p)=ad1(p)=ad2(p)=0;
if(l==r)
return;
int mid=(l+r)>>1;
build(lc(p),l,mid);
build(rc(p),mid+1,r);
pushup(p);
}
void add(int p,int l,int r,int ql,int qr,LL v1,LL v2)
{
if(ql<=l && qr>=r)
{
tree[p].add(v1,v2,r);
return;
}
spread(p,l,r);
int mid=(l+r)>>1;
if(ql<=mid)
add(lc(p),l,mid,ql,qr,v1,v2);
if(qr>mid)
add(rc(p),mid+1,r,ql,qr,v1,v2);
pushup(p);
}
void cov(int p,int l,int r,int ql,int qr,LL v)
{
if(ql<=l && qr>=r)
{
tree[p].cov(v);
return;
}
spread(p,l,r);
int mid=(l+r)>>1;
if(ql<=mid)
cov(lc(p),l,mid,ql,qr,v);
if(qr>mid)
cov(rc(p),mid+1,r,ql,qr,v);
pushup(p);
}
LL ask(int p,int l,int r,int pos)
{
if(l==r)
return dat(p);
spread(p,l,r);
int mid=(l+r)>>1;
if(pos<=mid)
return ask(lc(p),l,mid,pos);
return ask(rc(p),mid+1,r,pos);
}
int find(int p,int l,int r,int ql,int qr,LL v)
{
if(dat(p)<v)
return -1;
if(l==r)
return l;
spread(p,l,r);
int mid=(l+r)>>1;
if(ql<=mid && dat(lc(p))>=v)
return find(lc(p),l,mid,ql,qr,v);
if(qr>mid)
return find(rc(p),mid+1,r,ql,qr,v);
}
int main()
{
scanf("%d%d",&n,&C);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-(b+1);
build(1,1,m);
for(int i=1; i<=n; i++)
{
int x=lower_bound(b+1,b+1+m,a[i])-b;
if(x+1<=m)
add(1,1,m,x+1,m,-a[i],1);
if(x-1>=1)
{
add(1,1,m,1,x-1,C,0);
LL tmp=ask(1,1,m,x);
int pos=find(1,1,m,1,x-1,tmp);
if(pos!=-1)
cov(1,1,m,pos,x-1,tmp);
}
}
printf("%lld",ask(1,1,m,1));
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?