牛客練習賽13
阿新 • • 發佈:2018-03-17
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