码迷,mamicode.com
首页 > 其他好文 > 详细

【bestcoder #37】ABC题解

时间:2015-04-26 13:54:43      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:oi   bestcoder   贪心   思路题   

Rikka with string

Accepts: 395 Submissions: 2281
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
问题描述
众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:
有一天勇太得到了一个长度为n的字符串,但是六花一不小心把这个字符串搞丢了。于是他们想要复原这一个字符串。勇太记得这个字符串只包含小写字母而且这个串不是回文串。然而不幸的是他已经不记得这个字符串中的一些字符了,你可以帮他复原这个字符串吗?
当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?
输入描述
多组数据,数据组数不超过20,每组数据第一行两个正整数n。接下来一行一个长度为n的只包含小写字母和’?’的字符串,’?’表示勇太已经忘了这一个位置的字符了。
1≤n≤103
输出描述
每组数据输出仅一行一个长度为n的仅包含小写字母的字符串,如果有多种合法解,请输出字典序最小的,如果无解,请输出”QwQ”
输入样例
5
a?bb?
3
aaa
输出样例
aabba
QwQ

贪心的一直填a,知道最后一个”?”判断一下。

但是要注意如果最后一个”?”在字符串的中间,最后一个填什么都改变不了他是回文串的现实,所以要特殊处理一下。

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
using namespace std;
int n;
char s[1005];
int Judge()
{
    for (int i=1;i<=n;i++)
    {
        if (s[i]!=s[n-i+1]) return 0;
    }
    return 1;
}
int main()
{
    while (scanf("%d",&n)!=EOF)
    {
        scanf("%s",s+1);
        int l=0;
        for (int i=1;i<=n;i++)
            if (s[i]==‘?‘) l=i;
        if (!l&&Judge()) printf("QwQ\n");
        else
        {
            if ((n%2)&&l==(1+n)/2)
            {
                int p=0;
                for (int i=1;i<l;i++)
                    if (s[i]==‘?‘) p=i;
                if (!p&&Judge()) printf("QwQ\n");
                else
                {
                    for (int i=1;i<=n;i++)
                        if (s[i]==‘?‘) s[i]=‘a‘;
                    if (Judge())
                        s[p]=‘b‘;
                    for (int i=1;i<=n;i++)
                        printf("%c",s[i]);
                    printf("\n");
                }
            }
        else
        {
        for (int i=1;i<=n;i++)
        {
            if (s[i]==‘?‘&&i!=l)
                s[i]=‘a‘;
        }
        s[l]=‘a‘;
        if (Judge()) s[l]=‘b‘;
            for (int i=1;i<=n;i++)
                printf("%c",s[i]);
            printf("\n");
        }
        }
    }
    return 0;
}

Rikka with wood sticks

Accepts: 76 Submissions: 566
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
问题描述
众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:
勇太有一根长度为n的木棍,这个木棍是由n个长度为1的小木棍拼接而成,当然由于时间放置的久了,一些小木棍已经不牢固了,所以勇太想让六花把这个木棍分成正整数长度的4段,其中有3段要没有不牢固的小木棍,勇太希望这3段木棍的长度和可以最大。同时六花希望在满足勇太要求的情况下让这三根木棍能拼成一个三角形,请问萌萌哒六花有多少种可行的分割方案呢?
当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?
输入描述
多组数据,数据组数不超过20,每组数据第一行两个正整数n,m。接下来一行m个正整数分别描述了m个不牢固的小木棍位置(可能会有相同的位置)。
1≤n≤106,1≤m≤103
输出描述
每组数据输出仅一行一个正整数表示方案数。
输入样例
6 1
3
5 1
3
输出样例
2
0
Hint
两个方案不同当且仅当不存在一组断点的匹配使得每一组断点距离左端点的距离都相同(原木棍不可以翻转)。

要求三段都不能有不牢固的木棍,说明这三段一定是两头。

接下来就是各种讨论求构成三角形的方案。

由于没有开long long,被hack了。。

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#define LL long long
using namespace std;
int n,m;
int main()
{
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        int f=n+1,l=0;
        for (int i=1;i<=m;i++)
        {
            int x;
            scanf("%d",&x);
            f=min(f,x),l=max(l,x);
        }
        LL ans=0;
        int a=f-1,b=n-(l+1)+1;
        if (a<b) swap(a,b);
        if (a==b) 
        {
            puts("0");
            continue;
        }
        if (!b)
        {
            for (int i=1;i<a;i++)
            {
                int x=i,y=a-i;
                if (x>=y) break;
                else
                {
                    swap(x,y);
                    int k=(x-y)/2;
                    if (abs((x-k)-k)>=y) k++;
                    if (x/2>=k)
                        ans=ans+(x-2*k+2)-1;
                }
            }
        }
        else
        {
            for (int i=1;i<a;i++)
                if (abs(i-(a-i))<b) ans++;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

Rikka with sequence

Accepts: 34 Submissions: 144
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
问题描述
众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:
现在有一个序列,因为这个序列很任性,开始时空的。接下来发生了n个事件,每一个事件是以下两种之一:
1.勇太利用黑炎龙的力量在序列的开头、结尾以及每相邻两个元素之间都插入一个权值为w的元素。若第一步执行事件一,执行后数列仅有一个数字w.
2.勇太想要六花告诉他第L个元素到第R个中权值第k小的权值是多少。
当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?
输入描述
第一行一个正整数n。接下来n行每一行描述了一种操作:
1.如果输入格式是1 w,表示第一种事件。
2.如果输入格式是2 L R k,表示第二种事件。
1≤n≤105,1≤L≤R≤1018,1≤w≤109,保证L,R,k合法, R不会超过当前序列长度。
输出描述
对于每一个第二类事件,输出一个数字表示答案。
输入样例
6
1 3
1 1
2 2 3 2
1 2
2 3 5 2
2 1 4 4
输出样例
3
2
3

思路题。

把这个序列写一下可以发现,如果插入n个数(假设序列长度为2n?1),那么第i次插入的数在序列中出现了2i?1,并且是均匀分布的。

这也就说明在一个长度为k的询问区间中,最多会有logk种不同的数字。

我们把询问差分,暴力算出这logk个数在区间中的出现次数,再把这些数字排序,即可出解。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define LL long long
#define M 110000
using namespace std;
LL s[M];
int n,a[M],tot,id[M];
bool cmp(int x,int y)
{
    return a[tot-x]<a[tot-y];
}
void Add(LL x,int k)
{
    for (int i=0;i<=60;i++)
    {
        s[i]+=1LL*k*((x+1LL)/2LL);
        x/=2;
    }
}
int main()
{
    scanf("%d",&n);
    tot=70;
    while (n--)
    {
        int p;
        scanf("%d",&p);
        if (p==1)
        {
            int x;
            scanf("%d",&x);
            a[++tot]=x;
        }
        else
        {
            LL l,r,k;
            scanf("%I64d%I64d%I64d",&l,&r,&k);
            for (int i=0;i<=60;i++)
                s[i]=0,id[i]=i;
            Add(r,1),Add(l-1,-1);
            sort(id,id+1+60,cmp);
            LL now=0;
            for (int i=0;i<=60;i++)
                if (now+s[id[i]]>=k)
                {
                    printf("%d\n",a[tot-id[i]]);
                    break;
                }
                else now+=s[id[i]];
        }
    }
    return 0;
}

【bestcoder #37】ABC题解

标签:oi   bestcoder   贪心   思路题   

原文地址:http://blog.csdn.net/regina8023/article/details/45287321

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!