1. 程式人生 > >牛客練習賽13

牛客練習賽13

sig 字典序 end type 數位 大於等於 幸運 pos !=

幸運數字 I

定義一個數字為幸運數字當且僅當它的所有數位都是4或者7。
比如說,47、744、4都是幸運數字而5、17、467都不是。
現在,給定一個字符串s,請求出一個字符串,使得:
1、它所代表的整數是一個幸運數字;
2、它非空;
3、它作為s的子串(不是子序列)出現了最多的次數(不能為0次)。
請求出這個串(如果有多解,請輸出字典序最小的那一個)。

s中無4或7,輸出-1
4的個數大於等於7,輸出4
否則輸出7

幸運數字 II

定義一個數字為幸運數字當且僅當它的所有數位都是4或者7。
比如說,47、744、4都是幸運數字而5、17、467都不是。
定義next(x)為大於等於x的第一個幸運數字。給定l,r,請求出next(l) + next(l + 1) + ... + next(r - 1) + next(r)。

生成幸運數字,順序排列,二分求next(x),累加不同的next值即可。

註意:

  • 因為l最大可以為1000,000,000,所以幸運數字最少生成到4444,444,444才行
  • 生成方法有二:

    采用隊列,每次出隊元素為x,入隊x10+4, x10+7;

    next_permutation生成所有排列,下面代碼使用這種方法。

  • 生成的元素不多,可直接使用數組保存,並用lower_bound查找。這裏使用的是set,因為set就是一棵平衡二叉樹(紅黑樹),其自帶二分功能。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

set<ll> A;

void
init() { for(int nd = 1; nd <= 10; ++nd) { for(int n4 = nd; n4 >= 0; --n4) { int n7 = nd - n4; string ns = string(n4, ‘4‘) + string(n7, ‘7‘); while(next_permutation(ns.begin(), ns.end())) A.insert(atoll(ns.c_str())); A.insert(atoll(ns.c_str())); } } } int
main() { init(); ll a, b, ans = 0; cin >> a >> b; ll cur = a; while(cur <= b) { ll next = *A.lower_bound(cur); ans += (min(next, b) - cur + 1) * next; cur = next + 1; } cout << ans << endl; }

幸運數字 III

定義一個數字為幸運數字當且僅當它的所有數位都是4或者7。
比如說,47、744、4都是幸運數字而5、17、467都不是。
假設現在有一個數字d,現在想在d上重復k次操作。
假設d有n位,用d1,d2,...,dn表示。
對於每次操作,我們想要找到最小的x (x < n),使得dx=4並且dx+1=7。
如果x為奇數,那麽我們把dx和dx+1都變成4;
否則,如果x為偶數,我們把dx和dx+1都變成7;
如果不存在x,那麽我們不做任何修改。
現在請問k次操作以後,d會變成什麽樣子。

首先,笨的方法,肯定會循環,所以求循環節的長度,但字符串很長,所以hash。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;

int n, k;
char str[maxn];
map<unsigned, unsigned> Next;

unsigned Hash(char *s)
{
    unsigned hashval = 0;

    while(*s)
        hashval = *s++ + 31 * hashval;
    return hashval;
}

void operate()
{
    for(int i = 1; str[i]; ++i) {
        if(str[i] == ‘7‘ && str[i-1] == ‘4‘) {
            str[i] = str[i-1] = (i & 1) ? ‘4‘ : ‘7‘;
            break;
        }
    }
}

int loopLength(unsigned start)
{
    int cnt = 0;
    unsigned p = start;

    do {
        ++cnt;
        p = Next[p];
    } while(p != start);
    return cnt;
}

int main()
{
    scanf("%d%d%s", &n, &k, str);
    unsigned curHash = Hash(str);

    if(n == 1 || k == 0) {
        printf("%s\n", str);
    } else {
        while(k > 0) {
            //cout << str << " " << curHash << endl;
            operate();
            if(Next[curHash]) {
                for(k = (k+1) % loopLength(curHash); k > 0; --k)
                    operate();
                break;
            } else {
                curHash = Next[curHash] = Hash(str);
                --k;
            }
        }
        printf("%s\n", str);
    }
}

聰明的方法,什麽時候會循環,如何循環?

O為Odd奇數,E為Even偶數,考慮以下片段:
下標: ...OEO...
內容: ...477...
      ...447...
      ...477...
循環節為2,同理有以下片段:
下標: ...OEO...
內容: ...447...
      ...477...
      ...447...

所以就有代碼如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;

int n, k;
char s[maxn];

int main()
{
    scanf("%d%d%s", &n, &k, s + 1);

    for(int i = 1; i < n && k; ++i) {
        if(s[i] == ‘4‘ && s[i+1] == ‘7‘) {
            if(i & 1) {
                if(s[i+2] == ‘7‘) k %= 2;
                if(k) s[i+1] = ‘4‘, --k;
            } else {
                if(s[i-1] == ‘4‘) k %= 2;
                if(k) s[i] = ‘7‘, --k;
            }
        }
    }
    printf("%s\n", s+1);
}

幸運數字 IV

定義一個數字為幸運數字當且僅當它的所有數位都是4或者7。
比如說,47、744、4都是幸運數字而5、17、467都不是。
現在想知道在1...n的第k小的排列中,有多少個幸運數字所在的位置的序號也是幸運數字。

To be continued...

烏龜跑步

有一只烏龜,初始在0的位置向右跑。
這只烏龜會依次接到一串指令,指令T表示向後轉,指令F表示向前移動一個單位。烏龜不能忽視任何指令。
現在我們要修改其中正好n個指令(一個指令可以被改多次,一次修改定義為把某一個T變成F或把某一個F變成T)。
求這只烏龜在結束的時候離起點的最遠距離。(假設烏龜最後的位置為x,我們想要abs(x)最大,輸出最大的abs(x))

To be continued...

m皇後

在一個n*n的國際象棋棋盤上有m個皇後。
一個皇後可以攻擊其他八個方向的皇後(上、下、左、右、左上、右上、左下、右下)。
對於某個皇後,如果某一個方向上有其他皇後,那麽這個方向對她就是不安全的。
對於每個皇後,我們都能知道她在幾個方向上是不安全的。
現在我們想要求出t0,t1,...,t8,其中ti表示恰有i個方向是"不安全的"的皇後有多少個。 

To be continued...

牛客練習賽13