【CF】【每日一练】1140C+755C+511C+1154E

题目链接:传送门

【题意】:

给你n首歌,每首歌都有各自的长度length和美感beauty。

然后让你选择出最多k首出来,使得观赏度达到最大值。

观赏度  =  (选择的歌曲 的长度 )× (在所选歌曲中美感最低的)


【题解】:

其实一开始以为简单的排序,美感降序,然后选择之前的歌曲即可。

但是怎么确保前面K-1首,一定是时间总和最长呢???

这就用Set来维护,一直把时间最短的排出,在过程中取最大值即可。

#include<bits/stdc++.h>
#define F first
#define S second
#define mp(x,y) make_pair(x,y)
typedef long long ll;
#define PII pair<ll,ll>
const int N = 3e5+100;
using namespace std;
PII a[N];
bool cmp( PII u,PII v){
    return u.S > v.S ;
}
int main()
{
    ll n,k,u,v;
    cin >> n >> k ;
    for(int i=1;i<=n;i++){
        cin >> u >> v;
        a[i] = mp(u,v);
    }
    sort( a+1,a+1+n,cmp);
    set <PII> S;
    ll num = 0 ,cur = 0;
    ll ans = -1;
    PII tmp ;
    for(int i=1;i<=n;i++){
        cur = a[i].S;
        num = num + a[i].F;
        S.insert(mp(a[i].S,i));
        if ( S.size() > k ){
            auto it =  S.begin() ;
            num = num - it->first;
            S.erase(it);
        }
        ans = max( ans , num * cur );
    }
    printf("%lld\n",ans);
    return 0;
}

PolandBall and Forest

传送门

【题意】:

有很多树的节点,然后各自有一个方向,一些向左,一些向右。

每个节点都说自己是第a[i]个节点为一棵树的。

请问有多少颗树。

【题解】:

简单的并查集弄一下。别忘记了,记住find(i),因为过程中没有把所有的节点都聚在根节点上。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+100;
int pre[N];
int a[N];

int Find(int x){
    return x==pre[x] ? x : Find( pre[x] );
}

void Merge(int x,int y){
    int Fx = Find(x);
    int Fy = Find(y);
    if( Fx!=Fy ) {
        pre[Fx] = Fy;
    }
}
int vis[N]={0};
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        pre[i] = i;
        scanf("%d",&a[i]);
    }
    int ans = 0;
    for(int i=n;i>=1;i--){
        Merge(i,a[i]);
    }
    for(int i=1;i<=n;i++){
        if(vis[Find(i)]==0){
            ans ++;
            vis[Find(i)] = 1;
        }
    }
    printf("%d\n",ans);
    return 0;
}

 Serval and Parenthesis Sequence

题目链接:传送门

【题目】:

填?号,所有的前缀 (除整个字符串外)都不能是合法的括号序列。

首先有没有一个合法的填法?如果没有输出“:(”

如果有请输出那一种方案。

【题解】:

我发现这个题非常有趣,主要是因为我一直都没有想明白的如何贪心来填'?',其实把所有的左括号填完,再把所有的又括号填完即可,一点都不用关心那个所谓的前缀问题。只要在过程中加以判断即可。

原因是,只要第一个和最后一个是一对括号,中间的只要是合法即可。根据这样的想法出来的一定是符合题意的。

 

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+100;
char s[N];
int main()
{
    int n,f=1,cnt=0;
    scanf("%d",&n);
    scanf("%s",s);
    if( n&1 || (s[0]==')')|| (s[n-1]=='(')){
        f=0;
    }
    int L = 0,R = 0;
    for(int i=0;s[i];i++){
        if ( s[i] == '(')       L ++;
        else if ( s[i] == ')')  R ++;
    }
    L = n/2 - L;
    R = n/2 - R;
    int tmp=0;
    for(int i=0;s[i];i++){
        if( s[i]=='?' && L ){
            s[i] = '(' ;
            L--;
        }else if ( s[i]=='?' && R ){
            s[i] = ')' ;
            R--;
        }
        if(s[i]=='(') tmp++;
        else tmp--;
        if ( tmp==0 && s[i+1]!='\0' ) f=0;
    }
    f &= (tmp==0);
    f?printf("%s\n",s):printf(":(\n");
    return 0;
}

Two Teams

题目链接

【题意】:

就是两个教练选人,选人规则有2条。

1、最分数最高的

2、在附近(左和右)同时也选k个人

然后问:最后哪个人到了哪一个队伍。

【题解】:

用数组直接模拟这个移除的过程,然后用L[N],R[N]两个数组维护左右即可。

 

#include<bits/stdc++.h>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N = 2e5+100;
typedef pair<int,int> PII;
int L[N],R[N],ans[N],a[N],Ind[N];
int main()
{
    ios_base :: sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    int n,k;
    cin>>n>>k;
    set <int> S;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
        L[i] = i-1;
        R[i] = i+1;
        Ind[a[i]] = i;
        S.insert(a[i]);
    }

    int No = 0,K,tL,tR,tmp;
    while( !S.empty() ){
        auto it = S.end();
        it -- ;
        tmp = *it;
        No = (No)%2 + 1 ;

        K=k;
        //printf("It %d ,%d , L : %d , R : %d \n",Ind[tmp],tmp,L[Ind[tmp]],R[Ind[tmp]]);
        ans[Ind[tmp]] = No;
        tL = tR = Ind[tmp];
        for( int i = L[ Ind[tmp] ] ; K && i!=0; K--, i=L[i] ){
            //printf("##1 %d , %d  L : %d , R :%d \n",i,a[i],L[i],R[i]);
            ans[i] = No;
            tL = i ;
            S.erase(a[i]);
        }
        K=k;
        for( int i = R[ Ind[tmp] ] ; K && i!=n+1; K--, i=R[i] ){
            //printf("@@2 %d , %d  L : %d , R :%d \n",i,a[i],L[i],R[i]);
            ans[i] = No;
            tR = i;
            S.erase(a[i]);
        }

        S.erase(tmp);
        tL = L[tL] ;
        tR = R[tR] ;
        if( tL != 0 ){
            R[tL] = tR;
        }
        if( tR != n+1 ){
            L[tR] = tL;
        }

    }
    for(int i=1;i<=n;i++){
        printf("%d",ans[i]);
    }
    puts("");
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值