小R的调度
【问题描述】
小 R 是一名 OIer,她刚刚学习了逆序对的相关知识:对于一个长度为 n的
序列 A,其逆序对数定义为满足 i < j 且 A[i] > A[j]的(i, j)对数。
现在小 R 有一个长度为 n的 01序列 A,小 R每次可以交换 当前 A[i]与 A[j]
的值,并需要付出 c[i] + c[j]的代价。在若干轮(可以为空)交换后,小 R的得
分为最终 A序列的逆序对数减去她在交换中付出的代价之和。
小 R 想让最后的得分尽量大,你能帮帮她吗?
【输入】
第一行为一个正整数 n。
第二行为一个长度为 n的字符串,表示 01序列 A。
第三行为 n个整数 c[i],表示交换的代价参数。
【输出】
输出最大得分。
【输入输出样例】
inverse.in inverse.out
6
101010
1 1 1 1 1 1
7
【样例解释】
交换 A[2]和 A[5],付出 1 + 1 = 2 的代价。
最终序列为 111000,逆序对数为 9,得分为 9 - 2 = 7。
这道题有两个解法,DP我们就不说了,我也不会
然后就是贪心
看到这道题
我们要有两个基本的想法
(1)教皇的两个数只可能是一个0,一个1,同时0在前,1在后
(2)一个数只会被交换一次
然后我们可以先求出交换之后会有贡献的数对
然后扔到优先队列里,排序之后按顺序取,去完的就标记,知道取完为止
下面给出代码:
#include<iostream> #include<cstring> #include<algorithm> #include<string> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> using namespace std; inline int rd(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return ; } char a[100006]; int n; int c[100006]; struct node{ int x,y,z; bool operator < (const node c) const{ return z<c.z; } }f[100006]; priority_queue <node> q; int vis[100006]; int l[100006]; int main(){ n=rd(); scanf("%s",a+1); for(int i=1;i<=n;i++) c[i]=rd(); for(int i=1;i<=n;i++){ if(a[i]=='1') continue; for(int j=n;j>=i+1;j--){ if(a[j]=='0') continue; node v; v.z=j-i-c[i]-c[j]; v.x=i,v.y=j; q.push(v); } } int ans=0; while(!q.empty()){ node h=q.top(); q.pop(); if(!vis[h.x]&&!vis[h.y]&&h.z>0){ vis[h.x]=vis[h.y]=1; swap(a[h.x],a[h.y]); ans+=h.z-h.y+h.x; } } l[1]=0; for(int i=2;i<=n;i++){ if(a[i-1]=='1') l[i]=l[i-1]+1; else l[i]=l[i-1]; } for(int i=1;i<=n;i++) if(a[i]=='0') ans+=l[i]; printf("%d",ans); return 0; }
蒟蒻总是更懂你✿✿ヽ(°▽°)ノ✿
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步