2020/5/8—cf,我裂开来

呜呜呜我爆零了呜呜呜ljll

嗯T1T2防爆零的没了呜呜呜
在此纪念可怜的yjz大佬21发AC

 

 

 太惨了(逃

先来说说我们都有些啥题目吧。。。


T1

嗯,裂开了,当场裂开
我一看!桶排!
然后实现,嗯?嗯!嗯???不对啊,这怎么搞???

 第一发

嗯!输出错了!改!

 

第二发

 

我%^&*()_)(*&^

嗯。。。
我先调一调awa
嗯!找到了!估计能A了!

 

 

 这wtm。。。

开T2吧。。。

T2

嗯!大水题!

但是,我仔细一看!

正好n个?????
这。。。
瞬间就想到了一个不需要证明的贪心。。。
然后。。。

 

标准结局

 

我太难了
仔细一想,发现排个序就好了。。。
然后又调了亿调,就在比赛结束后一分钟的时候A了

这tm的。。。
我接下来看了看T3。。。

 

 

 就是一个dp。。。(第一想法)
这。。。
不行啊。

那就试试建图!2-sat!(第二想法)
这条件!我吐了,根本不行。。。
第三想法:炸了
然后一想。。。这绝对是个dp。。。
推了推式子,没搞出来。。。
这就是全部的心路历程。。。
我太难了 唉,开始写正解
T1

其实吧,就是一个排序能解决的事情,但是因为那个k的迷惑,我傻了。
想想排序,其实只要保证每一个字典序的接近就能找到最大值中的最小值了

直接构造 其实就是个贪心。。。
排个序

 

 

来自oi-wiki 这就是排序贪心的常见的情况之一

第一种情况

如果s[1]==s[k]

排序完了就能发现这个k与1之间是有联系的,只要他们不相同,因为排序的原因,就能够直接的说明在大的字符串就是s[k]。
问为什么的话,其实就是因为如果我在一个字符串中放这个字符,或者是将一类的字符放到其他的k个字符串中,易证,这个一定是可以在这种情况中最大的。
然后是另一种情况。

 


如果s[k+1]!=s[n]

那么在这种情况下,k个字符串中的第一个字符都是一样的。字典序的大小完全在于后面的字符串
为了保证这是一个最大的字符串,我不得不把下一个字符放在这个字符串上面。
只有这样,才能保证这个是最大中的最小。为了最大,我们一定要在他的后面加入一个字符,但是为了最小,又只能加入全部的字符。
比如对于

 

5 2
baacb

 

 这个样例就是这种情况。排序完是aabbc,最终的答案是abbc。
 最开始,我很疑惑。。。因为我觉得abc<abbc,然后我就傻了。。。
 但是在这种情况中,因为必须加入一个字符并最小,所以就会选择加入s[k+1].
  这个是很显然的。但是,之后为了使它继续保持在最大的情况下,我们不得不把全部比第一个字符大的字符加入它。
 因为如果有一个字符串得到了之后的字符,它就不会再这种情况中继续保持最大了。像abb和ac,ac就会大于abb了。
 因为大的字符越靠前,这个字符串的字典序就会越大,所以我们就要尽可能的把大的字符往后靠,也就是把小的字符往前填。
 所以就可以得到了awa

 第三种情况

 就是s[i]==s[k]&&s[k+1]==s[k]

 那就之间把第一个输出了,然后在选择几个字符输出就好了啊。。。这是最简单的。
 附上代码

 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
char s[1000001];
int k,n,T; 
inline ll read()
{
    char c=getchar();ll a=0,b=1;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
    for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;
    return a*b;
}
int main()
{
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    T=read();
    while(T--)
    {
        cin>>n>>k;
        scanf("%s",s+1);
        sort(s+1,s+n+1);
        if(s[k]!=s[1])
        {
            printf("%c\n",s[k]);
        }
        else
        if(s[n]!=s[k+1])
        {
            printf("%c%s\n",s[1],s+k+1);
        }
        else
        {
            cout<<s[1];
            for(int i=1;i<=(n-1)/k;i++)
            {
                printf("%c",s[k+1]);
            }
            cout<<endl;
        }
    }
    return 0;
}

 

 

 

 

就是这么简单

T2

 

 

 一看T2,无解输出-1,嗯,要记得,嗯。
然鹅!根本就没有无解的情况。。。极其可怕awa,来自cf的一波误导awa

转载于luogu的题解

要达到最少次数,贪心的想每次肯定加上最多的量 x * 2,然而每次最少加上变化过的x,所以最后一次加的数可能小于当前的x,但是没关系,可以让这次加上的那个小于x的数尽可能的往前移直到前一个数小于等于它,然后按照顺序求一遍答案即可。

这题比T1简单。。。
溜了,附上代码

 

void solve() {
    int n;
    scanf("%d", &n);
    vector<int> v;
    int x = 1;
    while(n > 0) {
        if(n > x) v.push_back(x);
        else v.push_back(n);
        n -= x;
        x <<= 1;
    }
    sort(v.begin(), v.end());
    printf("%d\n", v.size() - 1);
    for(int i = 1; i < v.size(); i++) {
        printf("%d ", v[i] - v[i - 1]);
    }
    puts("");
}

 

T2就好了。。

T3还没写awa

qwq

 

posted @ 2020-05-08 21:08  HL_ZZP  阅读(160)  评论(1编辑  收藏  举报