【bestcoder #37】ABC題解

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 個數(假設序列長度爲2n1 ),那麼第i 次插入的數在序列中出現了2i1 ,並且是均勻分佈的。

這也就說明在一個長度爲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;
}
發佈了315 篇原創文章 · 獲贊 26 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章