20240705比赛总结
T1 酸碱度中和
https://gxyzoj.com/d/hzoj/p/3731
因为是要将一些数变为一个值,所以差相对小的一些数修改的会更少,所以可以先将原数组排序
因为当x可以时,x+1必然可以,所以考虑二分
接下来考虑到因为上下变动的都至多为m,所以开头和结尾的差必然不超过2m
它就可以看作用一些长度为2m的版进行覆盖,问最少要多少块
显然,从1开始,然后在终点后的第一个点继续,暴力枚举即可
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
int n,k,a[100005];
bool check(int x)
{
int lst=-2e9-1,cnt=0;
for(int i=1;i<=n;i++)
{
if(a[i]-2*x>lst)
{
lst=a[i];
cnt++;
}
}
if(cnt<=k) return 1;
return 0;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
int l=0,r=a[n];
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))
{
r=mid;
}
else l=mid+1;
}
printf("%d",l);
return 0;
}
T2 聪明的小明
https://gxyzoj.com/d/hzoj/p/3732
很抽象的状压dp
5pts:k=m,在这种情况下,就是将很多一样的串拼在一起,答案显然是
50pts:因为此时只有0和1,考虑状压,将后面m位直接拼起来,然后进行转移即可
100pts:其实我们并不关注每个位置究竟是什么,因为这些就本质上是等价的
而且我们只用判断是否出现,所以只记录最后一位的位置即可
例如对于排列3,2,1,2,3,2,其实可以直接抽象为001101,所以直接状压
所以在初始状态,只需要将每一位的情况数相乘即可
在倒序枚举的情况下,显然,每出现一个1,可选的数量就+1
设
因为每一次转移,s都要去掉前面的一位,如果是1,则意味着有一种酒必须要加,所以只有一种情况
如果是0,则最后一位是什么都行,所以循环枚举即可
代码:
#include<cstdio>
#define ll long long
using namespace std;
int n,k,m,mod=998244353,dp[100005][1030],st[1030],cnt;
int get_sum(int x)
{
int res=0;
while(x)
{
if(x&1) res++;
x>>=1;
}
return res;
}
ll clac(int x)
{
ll num=0,res=1;
for(int i=0;i<m;i++)
{
if((x>>i)&1)
{
res=res*(k-num)%mod;
num++;
}
else res=res*num%mod;
}
return res;
}
int main()
{
scanf("%d%d%d",&n,&k,&m);
for(int i=1;i<(1<<m);i+=2)
{
int x=i;
if(get_sum(x)==k)
{
dp[m][x]=clac(x);
st[++cnt]=x;
}
}
int tmp=(1<<m)-1;
for(int i=m;i<n;i++)
{
for(int j=1;j<=cnt;j++)
{
int s=st[j];
if(!dp[i][s]) continue;
// printf("%d %d %d\n",i,s,dp[i][s]);
if((s>>(m-1))&1)
{
int tmp1=((s<<1)&tmp)|1;
dp[i+1][tmp1]=(dp[i+1][tmp1]+dp[i][s])%mod;
// printf("1:%d %d %d %d\n",i,s,tmp1,dp[i+1][tmp1]);
}
else
{
for(int t=0;t<m;t++)
{
if((s>>t)&1)
{
int tmp2=((s^(1<<t))<<1)|1;
dp[i+1][tmp2]=(dp[i+1][tmp2]+dp[i][s])%mod;
// printf("2:%d %d %d %d\n",i,s,tmp2,dp[i+1][tmp2]);
}
}
}
}
}
ll ans=0;
for(int i=1;i<=cnt;i++)
{
ans=(ans+dp[n][st[i]])%mod;
}
printf("%lld",ans);
return 0;
}
T3 线段树
https://gxyzoj.com/d/hzoj/p/3733
30pts:直接dfs枚举断点即可
100pts:假设在查询区间
此时,必然要递归
所以结论是,在你查询的过程中,“双边递归”的次数就是查询到的区间个数,所以我们就可以按照线段树上节点被“双边递归”的次数来dp
设
而cost指有多少个查询区间与
所以我们可以预处理出经过
预处理出包含
此时
代码:
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
int n,q;
ll cnt[505][505],w[505],dp[505][505];
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=q;i++)
{
int l,r;
scanf("%d%d",&l,&r);
cnt[l][r]++;
w[l]++,w[r]--;
}
for(int i=1;i<=n;i++) w[i]+=w[i-1];
for(int len=n;len>0;len--)
{
for(int i=1;i+len-1<=n;i++)
{
int j=i+len-1;
cnt[i][j]+=cnt[i-1][j]+cnt[i][j+1]-cnt[i-1][j+1];
}
}
for(int len=2;len<=n;len++)
{
for(int i=1;i+len-1<=n;i++)
{
int j=i+len-1;
dp[i][j]=1e18;
for(int k=i;k<j;k++)
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+w[k]-cnt[i][j]);
}
// printf("%d %d %d\n",i,j,dp[i][j]);
}
}
printf("%lld",q+dp[1][n]);
return 0;
}
T4 公路
https://gxyzoj.com/d/hzoj/p/3734
CSP-J2023 T2 的升级版,可以分为以下情况
首先,如果加完后可以直接到终点,且前面没有费用更少的,则直接加够到终点的量即可
如果前面有一个费用更少的且加一次油就能到,就直接加够到那个位置的量
如果无法到达,就将油加满,然后到它可到达的油价最小处加油,因为此处的油价一定比这里贵
重复此过程即可
可以先预处理出前面第一个费用更少的点和它可到达的油价最小处,然后直接计算
代码:
#include<cstdio>
#include<queue>
#define ll long long
using namespace std;
int n,nxt1[100005],nxt2[100005];
ll a[100005],v[100005],c,ans,sum;
deque<int> q;
int main()
{
scanf("%d%lld",&n,&c);
for(int i=2;i<=n+1;i++)
{
scanf("%lld",&v[i]);
v[i]+=v[i-1];
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
q.push_back(n);
for(int i=n-1;i>0;i--)
{
while(!q.empty()&&v[q.front()]-v[i]>c) q.pop_front();
nxt1[i]=q.front();
while(!q.empty()&&a[q.back()]>=a[i]) q.pop_back();
q.push_back(i);
}
for(int i=n-1;i>0;i--)
{
if(v[n+1]-v[i]<=c&&a[i]<a[nxt1[i]])
nxt1[i]=n+1;
}
nxt1[n]=n+1;
while(!q.empty()) q.pop_back();
q.push_back(1);
for(int i=2;i<=n+1;i++)
{
while(!q.empty()&&a[q.back()]>=a[i])
{
nxt2[q.back()]=i;
q.pop_back();
}
q.push_back(i);
}
int now=1;
while(now!=n+1)
{
if(v[nxt2[now]]-v[now]<=c)
{
ll dis=v[nxt2[now]]-v[now];
ans+=(dis-sum)*a[now];
sum=0,now=nxt2[now];
}
else
{
ans+=(c-sum)*a[now];
sum=c-v[nxt1[now]]+v[now];
now=nxt1[now];
}
// printf("%d %d\n",ans,now);
}
printf("%lld",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具