[36](CSP 集训)CSP-S 模拟 6
忌数与齐诸公子驰逐模拟赛。孙子见其算法不甚相远,代码有上、中、下、辈。于是孙子谓田忌曰:“君弟模拟赛,臣能令君胜。”田忌信然之,与王及诸公子赌千金。
及临质,“孙子曰:‘今以君之暴力与彼上等代码,取君上等代码与彼中等代码,取君中等代码与彼暴力。’既驰三题毕,而田忌一不胜而再胜,卒得王千金。”
A.一般图最小匹配
赛时可反悔贪心打出来了,但是不是在前缀和上维护的,所以爆了
直接 DP,\(f_{i,j}\) 表示前 \(i\) 个选了 \(j\) 对(注意到永远有 \(j\le \lfloor\frac{i}{2}\rfloor\)),转移显然
\[f_{i,j}=\min(f_{i-1,j},f_{i-2,j-1}+cost(i-1,i))
\]
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define abs(x) ((x)>0?(x):-(x))
int n,m,ans;
int a[5001];
int f[5001][5001];
signed main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
scanf("%lld %lld",&n,&m);
memset(f,0x3f,sizeof f);
for(int i=0;i<=n;++i) f[i][0]=0;
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
sort(a+1,a+n+1);
for(int i=2;i<=n;++i){
for(int j=1;j<=m;++j){
f[i][j]=min(f[i-1][j],f[i-2][j-1]+a[i]-a[i-1]);
}
}
int ans=0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=n;++i){
ans=min(ans,f[i][m]);
}
cout<<ans<<endl;
}
又到了赛时美丽代码时间
//smjb
//爱谁调谁调
//累了
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define abs(x) ((x)>0?(x):-(x))
int n,m,ans;
int a[5001];
//struct list{
// int l,r;
//}l[5001];
bool vis[5001];
//struct node{
// int left_node,right_node;
// int val;
// bool isfh;
// bool operator <(const node &A)const{
// if(val==A.val) return isfh<A.isfh;
// return val>A.val;
// }
//};
//priority_queue<node>q;
//vector<pair<int,int>>v;
struct node{
int left,right;
int val;
int morecost;
bool isfh;
bool operator <(const node &A)const{
if(val==A.val) return morecost>A.morecost;
return val>A.val;
}
};
priority_queue<node>q;
signed main(){
// ofstream cth("CON");
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
// freopen("data/v.in","r",stdin);
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
scanf("%lld %lld",&n,&m);
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
sort(a+1,a+n+1);
// cout<<"/";
for(int i=2;i<=n;++i){
q.push({i-1,i,abs(a[i]-a[i-1]),abs(a[i]-a[i-1]),false});
}
int ansm=0;
if(n==2*m){
for(int i=1;i<=n-1;i+=2){
ansm+=abs(a[i]-a[i+1]);
}
// cth<<ansm<<endl;
cout<<ansm<<endl;
return 0;
}
int cnt=0;
// cth<<"m== "<<m<<endl;
while(!q.empty()){
// cth<<"cnt"<<cnt<<endl;
if(cnt==m) break;
node u=q.top();q.pop();
if(u.isfh){
if(vis[u.left-1] or vis[u.right+1]) continue;
// cth<<"fh "<<u.left<<" "<<u.right<<" "<<u.val<<endl;
ans-=abs(a[u.left]-a[u.right]);
ans+=abs(a[u.left-1]-a[u.left])+abs(a[u.right]-a[u.right+1]);
vis[u.right+1]=true;
vis[u.left-1]=true;
cnt++;
}
else{
if(vis[u.left] or vis[u.right]) continue;
// cth<<u.left<<" "<<u.right<<endl;
vis[u.left]=true;
vis[u.right]=true;
ans+=abs(a[u.left]-a[u.right]);
if(u.left!=1 and u.right!=n) q.push({u.left,u.right,max(abs(a[u.left]-a[u.left-1]),abs(a[u.right]-a[u.right+1])),abs(a[u.left]-a[u.left-1])+abs(a[u.right]-a[u.right+1])-abs(a[u.right]-a[u.left]),true});
cnt++;
}
}
// cth<<"::: "<<m<<" "<<cnt<<endl;
if(m!=cnt){
// cth<<"in";
int ans1=0,ans2=0;
vector<int>ans_;
for(int i=1;i<=n-1;i+=2){
ans_.push_back(abs(a[i]-a[i+1]));
}
sort(ans_.begin(),ans_.end());
for(int i=0;i<=m-1;++i){
ans1+=ans_[i];
}
ans_.clear();
for(int i=n;i>=2;i-=2){
ans_.push_back(abs(a[i]-a[i-1]));
}
sort(ans_.begin(),ans_.end());
for(int i=0;i<=m-1;++i){
ans2+=ans_[i];
}
ans=min(ans1,ans2);
}
// cth<<ans<<endl;
cout<<ans<<endl;
// if(n==m*2)assert(ansm==ans);
// l[1].r=2;l[n].l=n-1;
// l[1].l=-1;l[n].r=-1;
// for(int i=2;i<=n-1;++i){
// l[i].l=i-1;l[i].r=i+1;
// q.push({i-1,i,a[i]-a[i-1],false});
// }
// q.push({n-1,n,a[n]-a[n-1],false});
// int cnt=0;
// while(!q.empty()){
// node u=q.top();q.pop();
// if(vis[u.left_node] or vis[u.right_node]){
// continue;
// }
// if(!u.isfh) v.push_back({u.left_node,u.right_node});
// else{
//
// }
// cth<<u.left_node<<" "<<u.right_node<<" "<<u.val+(u.isfh?a[u.right_node]-a[u.left_node]:0)<<endl;
// ans+=u.val+(u.isfh?a[u.right_node]-a[u.left_node]:0);cnt++;
// if(cnt==m) break;
// vis[u.left_node]=true;
// vis[u.right_node]=true;
// if(l[u.left_node].l!=-1) l[l[u.left_node].l].r=l[u.right_node].r;
// if(l[u.right_node].r!=-1) l[l[u.right_node].r].l=l[u.left_node].l;
// if(l[u.left_node].l!=-1 and l[u.right_node].r!=-1){
// cth<<"insert ["<<l[u.left_node].l<<" "<<l[u.right_node].r<<", "<<a[l[u.right_node].r]-a[l[u.left_node].l]<<"]"<<endl;
// q.push({l[u.left_node].l,l[u.right_node].r,a[l[u.right_node].r]-a[l[u.left_node].l],false});
// if(!u.isfh){
// q.push({l[u.left_node].l,l[u.right_node].r,
// abs(a[l[u.right_node].r]-a[u.right_node])+abs(a[u.left_node]-a[l[u.left_node].l])
// -abs(a[u.right_node]-a[u.left_node])-abs(a[l[u.right_node].r]-a[l[u.left_node].l]),true});
// cth<<"insert ["<<l[u.left_node].l<<" "<<l[u.right_node].r<<", fh "<<(a[l[u.right_node].r]-a[u.right_node])+abs(a[u.left_node]-a[l[u.left_node].l])-abs(a[u.right_node]-a[u.left_node])-abs(a[l[u.right_node].r]-a[l[u.left_node].l])<<"]"<<endl;
// }
// }
// }
// cout<<min(ans,ansm)<<endl;
}
B.重定向
啥玩意
从前往后贪心每一对数 \((i,i+1)\),注意到如果满足以下几点条件就可以直接选成被删的点(设 \(\min_i\) 为目前没填过的数字里最小的,这个东西可以用优先队列维护,首先找到哪些值没出现过,然后丢进小根堆,用了啥就 pop 出来)
- \(a_i=0\),且存在 \(j\),使得 \(j\gt i\) 且 \(a_j\lt \min_i\),则删掉 \(a_j\),这个 \(j\) 可以通过提前维护出后缀最小值来得到
- 否则,若 \(a_{i+1}=0\),如果 \(a_i\gt \min_i\),则删掉 \(a_i\)
- 否则,若 \(a_i\gt a_{i+1}\),删掉 \(a_i\)
知道删掉啥数以后就好做了,暴力填一遍就行了
#include<bits/stdc++.h>
using namespace std;
struct node{
int x;
bool operator <(const node& A)const{
return x>A.x;
}
};
priority_queue<node>q;
const int inf=1e9;
int t,n,a[200001],pos[200001],minn[200001];
bool cnt[200001];
int main(){
freopen("repeat.in","r",stdin);
freopen("repeat.out","w",stdout);
cin>>t;
while(t--){
scanf("%d",&n);
memset(cnt,0,sizeof cnt);
while(!q.empty()) q.pop();
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
cnt[a[i]]=1;
pos[a[i]]=i;
}
minn[n+1]=inf;
for(int i=n;i>=1;--i){
minn[i]=minn[i+1];
if(a[i]!=0) minn[i]=min(minn[i],a[i]);
}
for(int i=1;i<=n;++i){
if(!cnt[i]){
q.push({i});
}
}
int _pos=n;
for(int i=1;i<=n-1;++i){
if(!a[i]){
if(minn[i]>q.top().x){
a[i]=q.top().x;
q.pop();
}
else{
a[i]=minn[i];
_pos=pos[a[i]];
break;
}
continue;
}
if(a[i+1]){
if(a[i]>a[i+1]){
_pos=i;
q.push({a[i]});
break;
}
}
else{
if(a[i]>q.top().x){
_pos=i;
q.push({a[i]});
break;
}
}
}
for(int i=1;i<=n;++i){
if(a[i] or i==_pos){
continue;
}
a[i]=q.top().x;
q.pop();
}
for(int i=1;i<=n;++i){
if(i!=_pos) printf("%d ",a[i]);
}
putchar('\n');
}
}
/*
2
7
3 0 4 0 1 0 2
6
1 3 4 5 2 6
3 1 4 5 6 2
1 3 4 2 6
*/