十月 AT/CF

news/2024/10/13 10:20:12

ABC374 E

最大最小值,想到二分,问题是怎么 check。

其实就是对两个种有价值有重量的物品,求达到规定价值的最小重量。

只有两种物品,而且数据范围很小,考虑贪心。

假设 \(a\) 的性价比较高,\(b\) 的性价比较低,那么不可能选太多 \(b\)

也就是如果能用 \(a\) 代替的就用 \(a\) 代替。所以选 \(b\) 的总价值不能超过 \(lcm(a,b)\)。否则能用 \(a\) 替换更优。

发现 \(a\) 最大只有 \(100\),所以 \(b\) 最多选 \(100\) 个。暴力枚举。

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 105;
int n; LL X;
int a[N],b[N],p[N],q[N];bool check(int w)
{LL sum=0;for(int i=1;i<=n;i++){LL tmp=1e18;for(int j=0;j<=100;j++){int k=ceil((1.0*w-j*b[i])/a[i]); k=max(k,0);tmp=min(tmp,1ll*k*p[i]+1ll*j*q[i]);if(j*b[i]>w) break;}sum+=tmp;}return sum<=X;
}
int main()
{// freopen("in.in","r",stdin);// freopen("out.out","w",stdout);scanf("%d%lld",&n,&X);for(int i=1;i<=n;i++){scanf("%d%d%d%d",&a[i],&p[i],&b[i],&q[i]);if(a[i]*q[i]<b[i]*p[i]) swap(q[i],p[i]),swap(a[i],b[i]);}int l=0,r=1e9+7,ans=0;while(l<=r){int mid=(1ll*r-l>>1)+l;if(check(mid)) ans=mid,l=mid+1;else r=mid-1;}printf("%d\n",ans);return 0;
}

CF997 C2

有点难调。

容易发现是否合法只与 \(a\) 的元素在 \(b\) 中第一次出现的位置有关。

对于 \(a\) 序列来说,在 \(b\) 中的第一次出现的位置应该是单调递增的。

所以直接用 set 维护位置,每次更新就行。(不需要特殊处理第一个位置)

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
int T;
const int N = 2e5+5;
int n,m,q;
int a[N],b[N],ys[N];
set<int> p[N];
int main()
{// freopen("in.in","r",stdin);// freopen("out.out","w",stdout);scanf("%d",&T);while(T--){scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;i++) scanf("%d",&a[i]),p[a[i]].clear(),p[a[i]].insert(m+1),ys[a[i]]=i;for(int i=1;i<=m;i++){scanf("%d",&b[i]);}for(int i=1;i<=m;i++){p[b[i]].insert(i);}int res=0;for(int i=2;i<=n;i++) if(*p[a[i]].begin()<*p[a[i-1]].begin())res++;if(!res) printf("YA\n");else printf("TIDAK\n");while(q--){int x,y; scanf("%d%d",&x,&y);if(ys[b[x]]-1>=1&&*p[b[x]].begin()<*p[a[ys[b[x]]-1]].begin())res--;if(ys[b[x]]+1<=n&&*p[a[ys[b[x]]+1]].begin()<*p[b[x]].begin())res--;p[b[x]].erase(x);if(ys[b[x]]-1>=1&&*p[b[x]].begin()<*p[a[ys[b[x]]-1]].begin())res++;if(ys[b[x]]+1<=n&&*p[a[ys[b[x]]+1]].begin()<*p[b[x]].begin())res++;if(ys[y]-1>=1&&*p[y].begin()<*p[a[ys[y]-1]].begin())res--;if(ys[y]+1<=n&&*p[a[ys[y]+1]].begin()<*p[y].begin())res--;p[y].insert(x);if(ys[y]-1>=1&&*p[y].begin()<*p[a[ys[y]-1]].begin())res++;if(ys[y]+1<=n&&*p[a[ys[y]+1]].begin()<*p[y].begin())res++;b[x]=y;if(res==0) printf("YA\n");else printf("TIDAK\n");				}}
}

CF997 E1

出题人贴心地给出了 \(n^3\) 的范围。直接考虑 floyd。

跑完最短路后暴力枚举选的点就好,仍然是 \(n^3\) 暴力。

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
int T;
const int N = 405;
int n,m,q;
int f[N][N],a[N],now[N],ttt[N];
LL sum;
bool vs[N];
int main()
{// freopen("in.in","r",stdin);// freopen("out.out","w",stdout);scanf("%d",&T);while(T--){sum=0;scanf("%d%d%d",&n,&m,&q);memset(vs,0,sizeof(vs));memset(f,0x3f,sizeof(f));for(int i=1;i<=q;i++) scanf("%d",&a[i]);for(int i=1;i<=m;i++){int x,y,z; scanf("%d%d%d",&x,&y,&z);f[x][y]=f[y][x]=z;}for(int i=1;i<=n;i++) f[i][i]=0;for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)f[i][j]=min(f[i][j],max(f[i][k],f[k][j]));int fl=0;sum=1e18;for(int i=1;i<=n;i++){LL tmp=0;for(int j=1;j<=q;j++) tmp+=f[i][a[j]];if(sum>tmp){for(int j=1;j<=q;j++) now[j]=f[i][a[j]];sum=tmp; fl=i;}}vs[fl]=1;printf("%lld ",sum);for(int i=2;i<=n;i++){if(i>=q) {printf("0 "); continue;}fl=0;for(int j=1;j<=q;j++) ttt[j]=now[j];for(int j=1;j<=n;j++) if(!vs[j]){LL tmp=0;for(int k=1;k<=q;k++) tmp+=min(f[j][a[k]],now[k]);if(tmp<sum){for(int k=1;k<=q;k++) ttt[k]=min(f[j][a[k]],now[k]);sum=tmp; fl=j;}}for(int j=1;j<=q;j++) now[j]=ttt[j];vs[fl]=1; printf("%lld ",sum);}putchar('\n');}
}

CF997 E2

要求 \(n^2\) 的复杂度,发现问题是求路径上最大边权的最小值。考虑Kruskal 生成树

其实这个生成的是一个堆,将边权转化为点权,保证父亲的权值不小于儿子。

因此我们将问题转化为了树上问题,设计状态 \(f_{u,i}\) 表示以 \(u\) 为根的子树内有 \(i\) 个 servers。

从下向上更新,由于越往上权值越大,说明需要连接的最大边越大,所以需要连接的点一定尽量连深的点。

如果是 \(f_{son,0}\),说明儿子这棵子树内没有 servers,那么如果以 \(u\) 根这棵子树内有servers(\(f_{u,1/2/3\dots}\)),那么一定连这个更优。

此时最大边就是 \(va_u\)(根节点的权值),用子树内需要连接的点的个数(\(cnt_{son}\)) 乘上最大边就行。

如果以儿子为根的子树内已经有了,那直接相加更新就好。(\(f_{u,i+j}=\sum_i\sum_j f_{son_1,i}+f_{son_2,j}\)

然后你发现重构树会使点数翻倍,空间直接炸。

小 trick,发现最终答案只关心根 \(f_{1,i}\),所以 dp 数组用 vector,每更新完一个就返还空间,shrink_to_fit

code
#include<bits/stdc++.h>
using namespace std;
int T;
#define LL long long
const int N = 1e4+5;
const LL inf = 1e15;
int n,m,q;
int num;
struct E {int u,v,w;} ed[N];
int fa[N],son[N][2],va[N],cnt[N];
inline int find(int x) {return x==fa[x]?(x):(fa[x]=find(fa[x]));}
vector<LL> f[N];
void dfs(int u)
{if(!son[u][0]&&!son[u][1]) return ;dfs(son[u][0]); dfs(son[u][1]);f[u].resize(cnt[u]+1,inf);for(int i=1;i<=cnt[son[u][1]];i++) f[u][i]=min(f[u][i],1ll*va[u]*cnt[son[u][0]]+f[son[u][1]][i]);for(int i=1;i<=cnt[son[u][0]];i++) f[u][i]=min(f[u][i],1ll*va[u]*cnt[son[u][1]]+f[son[u][0]][i]);for(int i=1;i<=cnt[son[u][0]];i++)for(int j=1;j<=cnt[son[u][1]];j++)f[u][i+j]=min(f[u][i+j],f[son[u][0]][i]+f[son[u][1]][j]);f[son[u][0]].clear(); f[son[u][0]].shrink_to_fit();f[son[u][1]].clear(); f[son[u][1]].shrink_to_fit();
}int main()
{// freopen("in.in","r",stdin);// freopen("out.out","w",stdout);scanf("%d",&T);while(T--){scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n<<1;i++){f[i].clear(); f[i].resize(1,inf);cnt[i]=0; fa[i]=i; son[i][0]=son[i][1]=0;}for(int i=1,x;i<=q;i++) scanf("%d",&x),cnt[x]=1,f[x].resize(2,inf),f[x][1]=0;for(int i=1;i<=m;i++)scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);num=n;sort(ed+1,ed+1+m,[&](E &x,E &y){return x.w<y.w;});for(int i=1;i<=m;i++){int fx=find(ed[i].u),fy=find(ed[i].v);if(fx==fy) continue;fa[fx]=fa[fy]=++num; va[num]=ed[i].w; son[num][0]=fx; son[num][1]=fy; cnt[num]=cnt[fx]+cnt[fy];}dfs(num);for(int i=1;i<=q-1;i++) printf("%lld ",f[num][i]);for(int i=q;i<=n;i++) printf("0 ");putchar('\n');}return 0;
}

ABC374F

思路来自 int_R

假设物品发出时间是 \(s_i\),需求时间是 \(t_i\),那么答案就是 \(\sum s - \sum t\),发现后面是定值,可以直接处理。

我们要确定的就是所有物品发出时间的总和。

在能出发的时刻,要不然立即出发,要不然等下一个时刻出发,所以出发时间一定是 \(t_i+kx\),也就是从某一个 \(t_i\) 开始后连续发送几次 \(x\),然后等待。

设计状态 \(f_{i,j}\) 表示在 \(t_i\),第 \(i\) 个物品的状态从即将出发已经到达,此时还有 \(j\) 个物品没有出发(被跳过去了)。

转移即枚举这次运输会连续几个 \(x\),注意细节。

马蜂抽象。

code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 105,inf = 1e15;
int n,k,x,t[N],f[N][N],ans;main()
{freopen("in.in","r",stdin);freopen("out.out","w",stdout);scanf("%lld%lld%lld",&n,&k,&x);memset(f,0x3f,sizeof(f)); f[0][0]=0;for(int i=1;i<=n;i++) scanf("%lld",&t[i]),ans-=t[i];for(int i=1;i<=n;i++)//第 i-1 个到了,第 i 个将要发出时,还有 j 个没发出{for(int j=0;j<i;j++) f[i][j]=min(f[i-1][j],f[i][j]);for(int j=i;j>=1;j--) f[i][j]=f[i][j-1]; f[i][0]=inf;//第 i 个没发出,要加上。for(int j=1;j<=i;j++){int now=j,tm=t[i],sum=0,h=i+1;while(now){int cur=min(now,k);sum+=cur*tm; now-=cur; tm+=x;//发第 i 个。for(;h<=n&&t[h]<tm;h++) now++;f[h][now]=min(f[h][now],f[i][j]+sum);//第 i 个发完,该第 h 个了。}}}printf("%lld\n",ans+f[n+1][0]);return 0;
}

ABC375E

唐完了。。。

显然背包,发现数据范围较小,直接爆开四维 \(f_{i,j,k,h}\) 表示前 \(i\) 个物品,三组分别为 \(j,k,h\) 的最小交换次数,每个物品分讨放到哪组。

当然四维开不下,记录前缀和,把最后一维删掉,然后就做完了。

(WwW)

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 105;
int aim,n,v[N],s[N];
int pos[N];
int f[105][1505][1505],ans;
int main()
{// freopen("in.in","r",stdin);// freopen("out.out","w",stdout);scanf("%d",&n);memset(f,0x3f,sizeof(f));for(int i=1;i<=n;i++) scanf("%d%d",&pos[i],&v[i]),s[i]=s[i-1]+v[i];if(s[n]%3) return printf("%d\n",-1),0;aim=s[n]/3;f[0][0][0]=0;for(int i=1;i<=n;i++){for(int j=0;j<=s[i];j++){for(int k=0;k<=s[i]-j;k++){if(j>=v[i]) f[i][j][k]=min(f[i-1][j-v[i]][k]+(pos[i]!=1),f[i][j][k]);if(k>=v[i]) f[i][j][k]=min(f[i-1][j][k-v[i]]+(pos[i]!=2),f[i][j][k]);if(s[i]-k-j>=v[i]) f[i][j][k]=min(f[i-1][j][k]+(pos[i]!=3),f[i][j][k]);}}}if(f[n][aim][aim]<=1e9) printf("%d\n",f[n][aim][aim]);else printf("-1\n");return 0;
}

ABC373E

有点ex。

二分,然后考虑 check。

思路很简单,代码很抽象,还是太蔡了。

code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define P pair<LL,int>
#define fi first
#define se second
const int N = 2e5+5;
int n,m;
LL k,s[N],ans[N];
P a[N];bool check(LL mid,int p)
{int ls=n-m+1-(p>=n-m+1);(要算上自己)int rs=lower_bound(a+ls,a+1+n,make_pair(a[p].fi+mid+1,0))-a-1;(小于等于的个数)return ((rs-ls+1)*(a[p].fi+mid+1)-(s[rs]-s[ls-1]))-(mid+1)*(p>=n-m+1)>k-mid;//(注意最后要减去自己的贡献)
}int main()
{// freopen("in.in","r",stdin);// freopen("out.out","w",stdout);scanf("%d%d%lld",&n,&m,&k);if(m==n){for(int i=1;i<=n;i++) printf("%d ",0); putchar('\n');return 0;}for(int i=1;i<=n;i++) scanf("%lld",&a[i].fi),a[i].se=i;sort(a+1,a+1+n);for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i].fi;k=k-s[n];for(int i=1;i<=n;i++){LL l=0,r=k+1,res=0;while(l<=r){LL mid=l+r>>1;if(check(mid,i)) res=mid,r=mid-1;else l=mid+1;}if(res==k+1) ans[a[i].se]=-1;else ans[a[i].se]=res;}for(int i=1;i<=n;i++) printf("%lld ",ans[i]); putchar('\n');return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/70991.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

煤矿皮带运输智能监控系统

煤矿皮带运输智能监控系统基于视频AI图像识别算法,煤矿皮带运输智能监控系统通过实时监测皮带运输过程中的各种异常情况,如跑偏、撕裂、堆料异常等,实现对运输过程的智能监控。煤矿皮带运输智能监控系统一旦检测到异常情况,立即发出告警并采取相应的措施,以保障运输安全。…

2024-2025-1《计算机基础与程序设计》第3周学习总结20241428张雄一

学期(如2024-2025-1) 学号(如:20241300) 《计算机基础与程序设计》第X周学习总结 作业信息这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>(https://www.cnblogs.com/rocedu/p/9577842.html#WE…

パナソニックグループ プログラミングコンテスト2024(ABC 375)

形象理解这一场的 CA.Seats \(\text{diff }20\)对给定序列 \(S\) 找出 \(i\) 的个数,使得 \(S_{i}=0,S_{i+1}=1,S_{i+2}=0\)#define int long long string x;signed main(){int n;cin>>n;cin>>x;int ans=0;for(int i=0;i<=(int)x.length()-3;++i){if(x[i]==# an…

揭秘 FineVideo 数据集构建的背后的秘密

开放视频数据集稀缺,因此减缓了开源视频 AI 的发展。为此,我们构建了 FineVideo,这是一个包含 43,000 个视频的数据集,总时长为 3,400 小时,并带有丰富的描述、叙事细节、场景分割和问答对。 FineVideo 包含高度多样化的视频和元数据集合,使其成为训练模型理解视频内容、…

财务人的数字化转型

随着全球经济的变化,所有行业从过去的红利,过渡到向管理要红利,数字技术为经营和财务效率带来了令人惊喜的助推力,财务数字化成为企业转型的一个重要方向。 公司战略转型背后,财务组织如何长期落地? 数字化转型带来哪些实质性效益? 财务共享中心数字化建设现状 不同阶段…

多校 A 层冲刺 NOIP2024 模拟赛 06

多校A层冲刺NOIP2024模拟赛06 T 小 Z 的手套(gloves) 签到题 答案显然具有单调性,排序后二分答案即可。 T 小 Z 的字符串(string) 签到题 注意到 \(n\) 较小,可以使用 \(O(n^3)\) 的算法,直接上大 \(DP\)。 设计状态 \(f_{i,j,k,0/1/2}\) 表示从左往右填到 \(i\) 位,已…

Panasonic Programming Contest 2024(AtCoder Beginner Contest 375)

Panasonic Programming Contest 2024(AtCoder Beginner Contest 375)\(A\) A - Seats \(AC\)基础字符串。点击查看代码 int main() {int n,ans=0,i;string s;cin>>n>>s;for(i=0;i<n;i++){ans+=(s[i]==#&&s[i+1]==.&&s[i+2]==#&&i+2&l…