Codeforces Round #552 (Div. 3)每日两刷(E.Two Teams(vector),F. Shovels Shop(DP)G. Minimum Pos数论 2019/4/17

E. Two Teams

题目链接:
http://codeforces.com/contest/1154/problem/E

There are n students standing in a row. Two coaches are forming two teams — the first coach chooses the first team and the second coach chooses the second team.
The i-th student has integer programming skill ai. All programming skills are distinct and between 1 and n, inclusive.
Firstly, the first coach will choose the student with maximum programming skill among all students not taken into any team, and k closest students to the left of him and k closest students to the right of him (if there are less than k students to the left or to the right, all of them will be chosen). All students that are chosen leave the row and join the first team. Secondly, the second coach will make the same move (but all students chosen by him join the second team). Then again the first coach will make such move, and so on. This repeats until the row becomes empty (i. e. the process ends when each student becomes to some team).
Your problem is to determine which students will be taken into the first team and which students will be taken into the second team.

Input

The first line of the input contains two integers n and k (1≤k≤n≤2⋅105) — the number of students and the value determining the range of chosen students during each move, respectively.
The second line of the input contains n integers a1,a2,…,an (1≤ai≤n), where ai is the programming skill of the i-th student. It is guaranteed that all programming skills are distinct.

Output

Print a string of n characters; i-th character should be 1 if i-th student joins the first team, or 2 otherwise.

Examples
input

5 2
2 4 5 3 1

output

11111

input

5 1
2 1 3 5 4

output

22111

input

7 1
7 2 1 3 5 4 6

output

1121122

input

5 1
2 4 5 3 1

output

21112

Note

In the first example the first coach chooses the student on a position 3, and the row becomes empty (all students join the first team).
In the second example the first coach chooses the student on position 4, and the row becomes [2,1] (students with programming skills [3,4,5] join the first team). Then the second coach chooses the student on position 1, and the row becomes empty (and students with programming skills [1,2] join the second team).
In the third example the first coach chooses the student on position 1, and the row becomes [1,3,5,4,6] (students with programming skills [2,7] join the first team). Then the second coach chooses the student on position 5, and the row becomes [1,3,5] (students with programming skills [4,6] join the second team). Then the first coach chooses the student on position 3, and the row becomes [1] (students with programming skills [3,5] join the first team). And then the second coach chooses the remaining student (and the student with programming skill 1 joins the second team).

In the fourth example the first coach chooses the student on position 3, and the row becomes [2,1] (students with programming skills [3,4,5] join the first team). Then the second coach chooses the student on position 1, and the row becomes empty (and students with programming skills [1,2] join the second team).

题目大意:

给你n给球员,每个球员有自己的技能值,有两个教练,来选队员,每次选出剩下的最大的左边k个和右边k个和最大的本身,第一个教练先选,输出每个球员是哪个教练的。

题目思路:

先创另一个数组排序,然后从大到小循环这个数组,如果被选过了,就跳过,没有就找出左边k个和右边k个。用vector数组,每次找出最大值,就earse掉两边。#include
代码:

<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAX=2e5+10;
int a[MAX],vis[MAX],n,k,ans[MAX],b[MAX];
vector<int>pp;

int main(){
    scanf("%d %d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        pp.push_back(a[i]);
        b[i]=a[i];
        vis[a[i]]=i; //记录id
    }
    int op=1;
    sort(b,b+n);
    for(int j=n-1;j>=0;j--){
        int c=b[j];
        if(ans[vis[b[j]]]) continue;
        int p=find(pp.begin(),pp.end(),c)-pp.begin();
        int q=pp.size();
        int st=max(0,p-k),ed=min(p+k,q-1);
        for(int i=st;i<=ed;i++)
            ans[vis[pp[i]]]=op;
        pp.erase(pp.begin()+st,pp.begin()+ed+1);   //删除区间
        if(op==2)
            op=1;
        else op=2;
        }
    for(int i=0;i<n;i++){
        printf("%d",ans[i]);
    }
}

得用c++11,17会超时哈哈

F. Shovels Shop

There are n shovels in the nearby shop. The i-th shovel costs ai bourles.
Misha has to buy exactly k shovels. Each shovel can be bought no more than once.
Misha can buy shovels by several purchases. During one purchase he can choose any subset of remaining (non-bought) shovels and buy this subset.
There are also m special offers in the shop. The j-th of them is given as a pair (xj,yj), and it means that if Misha buys exactly xj shovels during one purchase then yj most cheapest of them are for free (i.e. he will not pay for yj most cheapest shovels during the current purchase).
Misha can use any offer any (possibly, zero) number of times, but he cannot use more than one offer during one purchase (but he can buy shovels without using any offers).
Your task is to calculate the minimum cost of buying k shovels, if Misha buys them optimally.

Input

The first line of the input contains three integers n,m and k (1≤n,m≤2⋅105,1≤k≤min(n,2000)) — the number of shovels in the shop, the number of special offers and the number of shovels Misha has to buy, correspondingly.
The second line of the input contains n integers a1,a2,…,an (1≤ai≤2⋅105), where ai is the cost of the i-th shovel.
The next m lines contain special offers. The j-th of them is given as a pair of integers (xi,yi) (1≤yi≤xi≤n) and means that if Misha buys exactly xi shovels during some purchase, then he can take yi most cheapest of them for free.

Output

Print one integer — the minimum cost of buying k shovels if Misha buys them optimally.

Examples
input

7 4 5
2 5 4 2 6 3 1
2 1
6 5
2 1
3 1

output

7

input

9 4 8
6 8 5 1 8 1 1 2 1
9 2
8 4
5 3
9 7

output

17

input

5 1 4
2 5 7 4 6
5 4

output

17

Note

In the first example Misha can buy shovels on positions 1 and 4 (both with costs 2) during the first purchase and get one of them for free using the first or the third special offer. And then he can buy shovels on positions 3 and 6 (with costs 4 and 3) during the second purchase and get the second one for free using the first or the third special offer. Then he can buy the shovel on a position 7 with cost 1. So the total cost is 4+2+1=7.
In the second example Misha can buy shovels on positions 1, 2, 3, 4 and 8 (costs are 6, 8, 5, 1 and 2) and get three cheapest (with costs 5, 1 and 2) for free. And then he can buy shovels on positions 6, 7 and 9 (all with costs 1) without using any special offers. So the total cost is 6+8+1+1+1=17.
In the third example Misha can buy four cheapest shovels without using any special offers and get the total cost 17.

题目大意:

给你n个商品,然后还有m个特价活动,你买满x件就把你当前的x件中最便宜的y件价格免费,问你买k件花最少的钱是多少

题目思路:

首先这个特价活动就像点外卖一样满多少减多少,你可以分几次来使用同一个优惠或者不同的优惠,然后我们我们分析三个点
1,那个特价活动中x>k的我们肯定都不会使用,因为那个时候已经买满了k件
2,我们肯定是买最便宜的k件来使用特价活动
3,我们其实可以当成分开几组来使用优惠,就像外卖有些时候要分几次来点才划得来一样
那么我们的思路就有了,我们dp[i]代表的是前i个物品的最高优惠价格,我们枚举最后一次使用特价活动是在哪个时候
为了方便我们用几个数组分别记录一些东西
s[i] 代表前i个的总花费
g[i] 代表买满i个最多能减少多少个物品值 (因为活动可能有重复,买i个减x个和y个,这个时候要取最优的情况)
dp[i] 代表的是前i个物品的最高优惠价格
我们枚举最后一次使用活动要枚举边界在哪,所以我们要使用二重循环枚举
状态转移方程
dp[i] 不买此优惠
dp[j]+dp[j]+s[j+g[i-j]]-s[j] 买此优惠
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAX=2e5+10;
ll n,m,k,p,q,s[MAX],g[MAX],dp[MAX],mon[MAX];

int main(){
     scanf("%lld %lld %lld",&n,&m,&k);
     for(int i=1;i<=n;i++){
        scanf("%lld",&mon[i]);
     }
     sort(mon+1,mon+n+1);
     for(int i=1;i<=k;i++){
        s[i]=s[i-1]+mon[i];  //记录前缀和
     }
     for(int i=1;i<=m;i++){
        scanf("%lld %lld",&p,&q);
        if(p>k) continue;
        if(g[p]<q) g[p]=q;
     }
     for(int i=1;i<=k;i++){
         for(int j=0;j<i;j++){  //枚举最后一次得特价活动位置
            dp[i]=max(dp[i],dp[j]+s[j+g[i-j]]-s[j]);
         }
     }
     cout<<s[k]-dp[k]<<endl;
}
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAX=2e5+10;
ll n,m,k,p,q,s[MAX],g[MAX],dp[MAX],mon[MAX];

int main(){
     scanf("%lld %lld %lld",&n,&m,&k);
     for(int i=1;i<=n;i++){
        scanf("%lld",&mon[i]);
     }
     sort(mon+1,mon+n+1);
     reverse(mon+1,mon+1+k);  //逆转
     for(int i=1;i<=k;i++){
        s[i]=s[i-1]+mon[i];  
     }
     for(int i=1;i<=m;i++){
        scanf("%lld %lld",&p,&q);
        if(p>k) continue;
        if(g[p]<q) g[p]=q;
     }
     for(int i=1;i<=k;i++){
            dp[i]=dp[i-1]+mon[i]; //不买优惠时
         for(int j=1;j<=i;j++){  //开始算买优惠是的最小总价
            dp[i]=min(dp[i],dp[i-j]+s[i-g[j]]-s[i-j]);
         }
     }
     cout<<dp[k]<<endl;
}

G. Minimum Possible LCM

题目链接:
http://codeforces.com/contest/1154/problem/G
You are given an array a consisting of n integers a1,a2,…,an.
Your problem is to find such pair of indices i,j (1≤i<j≤n) that lcm(ai,aj) is minimum possible.
lcm(x,y) is the least common multiple of x and y (minimum positive number such that both x and y are divisors of this number).

Input

The first line of the input contains one integer n (2≤n≤106) — the number of elements in a.
The second line of the input contains n integers a1,a2,…,an (1≤ai≤107), where ai is the i-th element of a.

Output

Print two integers i and j (1≤i<j≤n) such that the value of lcm(ai,aj) is minimum among all valid pairs i,j. If there are multiple answers, you can print any.

Examples
input

5
2 4 8 3 6

output

1 2

input

5
5 2 11 3 7

output

2 4

input

6
2 5 10 1 10 2

output

1 4

题目大意:

从n个数中选出2个数,使得这两个数的最小公倍数最小

题目思路:

LCM(a,b) = a * b / gcd(a,b);考虑枚举公因数d,假设n个数中具有因子d的数分别是x1,x2,x3,x4…(x1 < x2 < x3 < x4 …)

如果x1 与 x2 的最大公因数就是d,那么lcm(x1,x2) = x1*x2/d,如果x4 与 x1 的最大公因数也是d,那么x4*x1/d一定大于x1*x2/d,所以后面的就不用考虑了

如果x1 与x2 的最大公因数不是d,那么lcm(x1,x2) 一定小于x1*x2/d,即使x4 与 x1的最大公因数是d,那么x4*x1/d一定大于lcm(x1,x2),同样后面也不用考虑了

所以我们只需要得到每个d的倍数的前2项即可,时间复杂度(1e7*log(le7))
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAX=1e7+17;
int a[MAX],pos[MAX],n,v,x,y;

int main(){
   scanf("%d",&n);
   ll res=1e18;
   for(int i=1;i<=n;i++){
    scanf("%d",&v);
    a[v]++;
    if(a[v]>1&&v<res){
        res=v;
        x=pos[v];
        y=i;
        }
    pos[v]=i;
   }
   for(int i=1;i<MAX;i++){
    int val=0;
    for(int j=i;j<MAX;j+=i){
        if(!a[j]) continue;
        if(!val) val=j;
        else{
            ll g=__gcd(val/i,j/i);
            if(g==1){
                ll lcm=1LL*j/i*val;
                if(lcm<res){
                    res=lcm;
                    x=pos[val];
                    y=pos[j];
                    }
                }
        break;
            }
        }
    }
    if(x>y)swap(x,y);
    cout<<x<<" "<<y<<endl;
}

猜你喜欢

转载自blog.csdn.net/qq_43333395/article/details/89379882