CodeForces - 1257E *
给出三组数长度分别为k1,k2,k3,每次可以移动一个数到另一个组,问最少需要几次可以让三个组的分别排序后按k1,k2,k3的顺序正好是1到(k1+k2+k3)的顺序
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
long long dp[200010][4];
int a[200010];
int main()
{
int n,k1,k2,k3,m;
cin>>k1>>k2>>k3;
n=k1+k2+k3;
for(int i=1;i<=k1;i++)
{
cin>>m;
a[m]=1;
}
for(int i=1;i<=k2;i++)
{
cin>>m;
a[m]=2;
}
for(int i=1;i<=k3;i++)
{
cin>>m;
a[m]=3;
}
memset(dp,INF,sizeof(dp));
dp[0][1]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=3;j++)
{
for(int k=j;k<=3;k++)
{
if(a[i]!=k)
dp[i][k]=min(dp[i][k],dp[i-1][j]+1);
else
dp[i][k]=min(dp[i][k],dp[i-1][j]);
}
}
}
cout<<min(dp[n][1],min(dp[n][2],dp[n][3]))<<endl;
return 0;
}
dp[i][k]表示把第 i 个数从 j 组移到 k 组,k 从 j 开始循环保证了第 i 个数所属的组一定大于第 i-1 个数所在的组
CodeForces - 1256E
有n个人,进行分组,每组的值为最大减最小,每组最少三个人,求怎么分可以使所有组值之和最小
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int l[200010],dp[200010],ans[200010];
struct node{
int v,id;
}a[200010];
bool cmp(node a,node b)
{
return a.v<b.v;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].v);
a[i].id=i;
}
memset(dp,INF,sizeof(dp));
sort(a+1,a+n+1,cmp);
dp[0]=0;
for(int i=1;i<=n;i++)
{
for(int j=3;j<=5;j++)
{
int t=dp[i-1]+a[i+j-1].v-a[i].v;
if(dp[i+j-1]>t)
{
dp[i+j-1]=t;
l[i+j-1]=i;
}
}
}
int pos=n,num=0;
while(pos)
{
num++;
for(int i=l[pos];i<=pos;i++)
ans[a[i].id]=num;
pos=l[pos]-1;
}
cout<<dp[n]<<" "<<num<<endl;
for(int i=1;i<=n;i++)
cout<<ans[i]<<" ";
cout<<endl;
return 0;
}
dp部分没什么好说的,就是每组3-5人,主要是要给出的顺序输出每个人属于第几组,可以设一个左边界数组,每次 i 是有边界,l [ i ] 就是第 i 个数所在组的左边界,最后再赋值,注意到题目的组分法是从大到小的,所以pos=n反向赋值,根据他的编号id记录他在第几组,最后输出ans[i],而不是ans[a[i].id],因为未排序后第 i 个并不是排序前的第 i 个,以第二个样例为例6 1 5 12 13 2 15,排序前a3.v=12,a3.id=3,排序后a4.v=12,a4.id=3,然后ans[ a4.id ]=ans[ 3 ]=1,即原顺序的第三个数属于第一组,而ans[ a3.id ]=a[ 2 ]=2是原顺序的第二个。
CodeForces - 1260E
n个人打拳,能力是1到n,两个分组对比,弱的人出局,收买第i个人需要 ai 钱,问最小花费得冠军
#include <iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int N=(1<<18)+5;
int a[N];
int main()
{
priority_queue<int,vector<int>,greater<int> >q;
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
ll ans=0;
int i;
while(n>1)
{
if(a[n-1]==-1) break;
q.push(a[n-1]);
ans+=q.top();
q.pop();
for( i=n-2;i>=n>>1;i--)
{
if(a[i]==-1) break;
q.push(a[i]);
}
if(i>=n>>1) break;
n=n>>1;
}
printf("%lld\n",ans);
}
CodeForces - 1272E
n个数,第 i 个可以跳到 i+ai 或 i-ai ,问最少跳几次可以 第 i 个数奇偶性不同
#include<bits/stdc++.h>
using namespace std;
#define pt(a) cerr<<a<<"---\n"
const int maxn=2e5+99;
const int INF=1<<30;
struct node{int v,a,b;}G[maxn];
vector<int> v[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n; cin>>n;
for(int i=1;i<=n;++i){
G[i].a=G[i].b=INF;
cin>>G[i].v;
if(i+G[i].v<=n) v[i+G[i].v].push_back(i);
if(i-G[i].v>=1) v[i-G[i].v].push_back(i);
}
queue<int> que;
for(int i=1;i<=n;++i) que.push(i);
while(!que.empty()){
int x=que.front(); que.pop();
for(int i:v[x]){
if(G[x].v&1){
if(G[i].a>1||G[i].b>G[x].b+1){
G[i].a=1;
if(G[i].b>G[x].b+1) G[i].b=G[x].b+1;
que.push(i);
}
}else{
if(G[i].b>1||G[i].a>G[x].a+1){
G[i].b=1;
if(G[i].a>G[x].a+1) G[i].a=G[x].a+1;
que.push(i);
}
}
}
}
for(int i=1;i<=n;i++){
if(G[i].v&1) cout<<(G[i].b==INF?-1:G[i].b)<<' ';
else cout<<(G[i].a==INF?-1:G[i].a)<<' ';
}
return 0;
}
CodeForces - 1251D
给 n 个人发工资,总数 s ,每个人工资为一个范围,求怎么发可以使工资的中位数最大
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
struct Node {
int l,r;
}a[maxn];
int n;
ll s;
bool check(int mid) {
vector<int>now;
ll num = 0;
int cnt = 0,res = (n + 1) / 2;
for(int i = 1;i <= n;i++) {
if(a[i].l >= mid) {
cnt++;
num += a[i].l;
}
else if(a[i].r < mid) {
num += a[i].l;
}
else {
num += a[i].l;
now.push_back(mid - a[i].l);
}
}
if(cnt + now.size() < res) return false;
sort(now.begin(),now.end());
for(int i = 0;i < max(0,res - cnt);i++) {
num += now[i];
}
if(num <= s) return true;
return false;
}
int main() {
int T;scanf("%d",&T);
while(T--) {
scanf("%d%lld",&n,&s);
int mi = 1e9,mx = 0;
for(int i = 1;i <= n;i++) {
scanf("%d%d",&a[i].l,&a[i].r);
mi = min(a[i].l,mi);
mx = max(a[i].r,mx);
}
int l = mi,r = mx;
int ans = mi;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid)) {
ans = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
printf("%d\n",ans);
}
return 0;
}
CodeForces - 1251E2
n 个投票的人,第 i 个人会投给你如果已经有 mi 个人投给你,否则需要 pi 收买,问最少多少钱获得全部选票
#include <bits/stdc++.h>
using namespace std;
const int maxn =2e5+50;
typedef long long ll;
vector<ll>v[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=0;i<=n;i++) v[i].clear();
for(int i=1;i<=n;i++)
{
int m;ll p;
cin>>m>>p;
v[m].push_back(p);
}
priority_queue<ll,vector<ll>,greater<ll> > pq;
ll ans =0;
for(int i=n-1;i>=0;i--)
{
for(int j=0;j<v[i].size();j++)
{
pq.push(v[i][j]);
}
while(pq.size()>n-i)
{
ans += pq.top();
pq.pop();
}
}
cout<<ans<<endl;
}
return 0;
}