4.11省选模拟

T1

想到了优化前的dp

40pts无优化

#include<bits/stdc++.h> #define INF 2147483647 #define MAXN 1005 using namespace std; int n,a[MAXN],dp[MAXN],Max[MAXN],Mid[MAXN]; int main() { freopen("separate.in","r",stdin); freopen("separate.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); Max[i]=max(Max[i-1],a[i]); } memset(dp,0x3f,sizeof(dp)); dp[0]=0; for(int i=1;i<=n;i++) { memcpy(Mid,dp,sizeof(dp)); memset(dp,0x3f,sizeof(dp)); for(int j=0;j<i;j++) { int now; if(a[i]>=a[j]) now=i; else now=j; dp[now]=min(dp[now],Mid[j]+a[now]); dp[j]=min(dp[j],Mid[j]+Max[i]); //其实转移就有两种 //第二个整体加不管 //第一个也分为两种情况,如果a[j]>a[i]那么所有大于a[i]的位置区间加a[j] //貌似是可以用线段树维护的,但是太麻烦,或许也能cdq或者决策单调性? //弃了,40跑路. } } int Ans=INF; for(int i=0;i<=n;i++) { Ans=min(Ans,dp[i]); } cout<<Ans<<"\n"; }

把转移写出来

重新考虑一下我们这一维的含义,其实可以看成是第二维表示成数字大小

那么

dp[i][j]表示前i个点,一个序列末端是j,另一个序列末端是s[i]的最小士气值

转移易得

a[i+1]>s[i],dp[i+1][j]=dp[i][j]+a[i+1]

a[i+1]<=s[i]

Sit1:

a[i+1]<j,dp[i+1][j]=dp[i+1][j]+j区间加等差数列

Sit2

a[i+1]>=j,dp[i+1][a[i+1]]=dp[i][j]+a[i+1]找一个区间最小值加进去

dp[i+1][j]=dp[i][j]+s[i]区间加

由于区间加等差数列可以看成斜率,找一个凸包最下面的点就好了,显然

直接大力分块,维护凸包即可

#define Eternal_Battle ZXK #include<bits/stdc++.h> #define INF 0x3f3f3f3f3f3f3f3f #define ll long long #define MAXN 70001 #define MAXM 1001 using namespace std; int blo,sy[MAXN],L[MAXM],R[MAXM],nowp[MAXM]; int n,a[MAXN],s[MAXN]; ll lazy[MAXM],mx[MAXM],val[MAXN],ch[MAXM]; vector<int> vec[MAXM]; inline double slope(int x,int y) {return 1.0*(val[x]-val[y])/(x-y);} void push_down(int x) { for(int i=L[x];i<=R[x];++i) val[i]+=1ll*i*ch[x]+lazy[x]; ch[x]=lazy[x]=0; } void remake(int x) { push_down(x); vec[x].clear(); for(int i=L[x];i<=R[x];++i) { if(vec[x].size()&&val[i]>=val[vec[x][vec[x].size()-1]]) continue; while(vec[x].size()>1&&slope(i,vec[x][vec[x].size()-1])<=slope(vec[x][vec[x].size()-1],vec[x][vec[x].size()-2])) vec[x].erase(--vec[x].end()); vec[x].push_back(i); } nowp[x]=vec[x].size()-1; mx[x]=val[vec[x][nowp[x]]]; } void repair(int x) { while(nowp[x]!=0&&val[vec[x][nowp[x]]]+ch[x]*vec[x][nowp[x]]>=val[vec[x][nowp[x]-1]]+ch[x]*vec[x][nowp[x]-1]) --nowp[x]; mx[x]=val[vec[x][nowp[x]]]+ch[x]*vec[x][nowp[x]]; } ll query(int l,int r) { ll res=INF; if(sy[l]==sy[r]) { repair(sy[l]); for(int i=l;i<=r;++i) res=min(res,i*ch[sy[i]]+val[i]+lazy[sy[i]]); return res; } for(int i=sy[l];i<=sy[r];++i) repair(i); for(int i=l;i<=R[sy[l]];++i) res=min(res,i*ch[sy[i]]+val[i]+lazy[sy[i]]); for(int i=r;i>=L[sy[r]];--i) res=min(res,i*ch[sy[i]]+val[i]+lazy[sy[i]]); for(int i=sy[l]+1;i<sy[r];++i) res=min(res,mx[i]+lazy[i]); return res; } void add(int l,int r,int v) { if(sy[l]==sy[r]) { for(int i=l;i<=r;++i) val[i]+=v; remake(sy[l]); return; } for(int i=l;i<=R[sy[l]];++i) val[i]+=v; for(int i=r;i>=L[sy[r]];--i) val[i]+=v; remake(sy[l]);remake(sy[r]); for(int i=sy[l]+1;i<sy[r];++i) lazy[i]+=v; return ; } void addc(int l,int r) { if(sy[l]==sy[r]) { for(int i=l;i<=r;++i) val[i]+=i; remake(sy[l]); return; } for(int i=l;i<=R[sy[l]];++i) val[i]+=i; for(int i=r;i>=L[sy[r]];--i) val[i]+=i; remake(sy[l]);remake(sy[r]); for(int i=sy[l]+1;i<sy[r];++i) ch[i]++; return ; } void re() { for(int i=1;i<=sy[n];++i) push_down(i); for(int i=1;i<=sy[n];++i) remake(i); } void out() { re(); // cout<<sy[i]<<" "<<L[sy[i]]<<" "<<R[sy[i]]<<endl; for(int i=0;i<=n;++i) cout<<val[i]<<" "; cout<<endl; } inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } signed main() { freopen("separate.in","r",stdin); freopen("separate.out","w",stdout); memset(val,0x3f,sizeof(val)); val[0]=0; n=read(); for(int i=1;i<=n;++i) a[i]=read(); blo=sqrt(n); for(int i=0;i<=n;++i) { sy[i]=(i/blo)+1; if(!L[sy[i]]) L[sy[i]]=i; R[sy[i]]=i; } L[1]=0; for(int i=1;i<=sy[n];++i) remake(i); for(int i=1;i<=n;++i) s[i]=max(s[i-1],a[i]); for(int i=0;i<n;++i) { if(a[i+1]>s[i]) { add(0,a[i+1],a[i+1]); } else { if(a[i+1]+1<=s[i]) addc(a[i+1]+1,s[i]); ll p=query(0,a[i+1])+a[i+1]; if(0<=a[i+1]-1) add(0,a[i+1]-1,s[i]); push_down(sy[a[i+1]]); val[a[i+1]]=p; remake(sy[a[i+1]]); } } for(int i=1;i<=sy[n];++i) remake(i); ll res=INF; for(int i=0;i<=n;++i) res=min(res,val[i]); cout<<res; }

T2

正解竟然是搜索....貌似是基于border集合大小有限得出的

暴力dfs

#include<bits/stdc++.h> using namespace std; int n,k,Fin,Ans[1000]; void dfs(int now) { if(now==n+1) { int res=0; for(int j=2;j<=n;j++) { int len=0; while(Ans[1+len]==Ans[j+len]) len++; res=max(res,len); } Fin+=res; return ; } for(int i=1;i<=k;i++) { Ans[now]=i; dfs(now+1); } } int main() { freopen("lorem.in","r",stdin); freopen("lorem.out","w",stdout); scanf("%d%d",&n,&k); dfs(1); cout<<Fin<<"\n"; }

正解需要Border理论,不会

T3

重新透彻了一下模拟费用流,考场上一直误以为是dp,导致根本没想到

其实dp的过程就是找匹配,思想很接近模拟费用流了,但是没有转化到匹配上

粘一下暴力dp

#include<bits/stdc++.h> #define int long long #define MAXN 1005 #define INF LLONG_MAX using namespace std; int a[MAXN],b[MAXN],Ans=INF,n,k; int dp[MAXN][MAXN],Min[MAXN][MAXN],Mid[MAXN][MAXN]; signed main() { freopen("world.in","r",stdin); freopen("world.out","w",stdout); scanf("%lld%lld",&n,&k); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } for(int i=1;i<=n;i++) { scanf("%lld",&b[i]); } // if(n>1000) // { // priority_queue<int,vector<int>,greater<int> >q; // for(int i=1;i<=n;i++) // { // q.push(a[i]+b[i]); // } // int cnt=k,Ans=0; // while(cnt--) // { // Ans+=q.top(); // q.pop(); // } // cout<<Ans; // return 0; // } memset(dp,0x3f,sizeof(dp)); dp[0][0]=0; for(int i=1;i<=n;i++)//枚举目前选到哪个位置了 { memcpy(Mid,dp,sizeof(Mid)); // memset(dp,0x3f,sizeof(dp)); for(int j=0;j<=min(i-1,k-1);j++)//枚举我们目前选了几个人了 { // for(int z=j;z<i;z++)//枚举上面一层上一个选的是哪个 // { for(int v=j+1;v<=i;v++) { dp[j+1][v]=min(dp[j+1][v],min(Mid[j+1][v],Mid[j][v-1]+a[v]+b[i])); dp[j+1][v]=min(dp[j+1][v],dp[j+1][v-1]); if(j+1==k) { Ans=min(Ans,dp[j+1][v]); } continue; } // dp[j+1][Min[z+1][i]]=min(dp[j+1][Min[z+1][i]],dp[j][z]+a[Min[z+1][i]]+b[i]); // //区间是z+1,i // } } } cout<<Ans<<"\n"; }

正解

#define Eternal_Battle ZXK #include<bits/stdc++.h> #define INF 10000000000 #define int long long #define MAXN 500005 using namespace std; int a[MAXN],b[MAXN],Sum,num,n,k; priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q; bool check(int mid) { while(q.size())q.pop(); int res=0; num=0; Sum=0; for(int i=1;i<=n;i++) { q.push(make_pair(a[i],0)); int now=q.top().first; int id=q.top().second; // cout<<now<<" "<<id<<"\n"; if(b[i]+now+mid>0) { continue; } Sum+=b[i]+now+mid; if(id==0) num++; q.pop(); q.push(make_pair(-b[i]-mid,1)); } return num>=k; } signed main() { freopen("world.in","r",stdin); freopen("world.out","w",stdout); scanf("%lld%lld",&n,&k); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=1;i<=n;i++) scanf("%lld",&b[i]); int l=-INF,r=INF,mid,Ans=0; while(l<=r) { int mid=(l+r)>>1; //如果大于等于返回true if(check(mid)) { l=mid+1; Ans=mid; } else { r=mid-1; } } check(Ans); cout<<Sum-k*Ans<<"\n"; }

__EOF__

本文作者Eternal_Battle
本文链接https://www.cnblogs.com/Eternal-Battle/p/16130719.html
关于博主:这个世界除了你,都知道我喜欢你
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Gnomeshgh_k  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示