国庆清北刷题冲刺班 Day6 上午

来源:互联网 发布:音频制作软件下载 编辑:程序博客网 时间:2024/04/28 19:55

1. 角谷猜想

(kakutani.pas/c/cpp)
(kakutani.in/out)
时间限制:1s/空间限制:256M
【题目描述】
某个名字末尾是 654321 的小 A 同学是个大家眼中公认的学霸(虽然他永远
不承认),他对题目的直觉到了一种可怕的地步,一眼看出题目的算法对他而言
只是小 Case,他甚至能在看到一个证明的瞬间敏锐地判断出这个证明的真伪。
现在小 A 同学机缘巧合地看到了角古猜想 (即对于 x 当它为奇数则 1 3   x x ,
为偶数,则
2
x
x  ,一直重复这个步骤,则 x 最终会变为 1),在看完这个猜想的
一瞬间,他的直觉就来了——他认为角古猜想一定是错的!然后——他立刻就能
找出反例!
他立刻在纸上写满了 ) 00 10 1 (   n n 个小于 ) 10 0 ( 10
4
  L
L
的正整数, 打算放
到他的 grand super computer 上去跑,可是他突然觉得有些正整数不是很吉利,
可能会干扰到他的最终结果,所以他打算把一些正整数加工一下。
小 A 觉得 4、7、13 都是不吉利的数字,所以要把所有正整数里的 4、7、13
都去掉,如果去掉后得到的新数字里依旧有 4、7、13,那么就要继续删掉,直
到最后的数组不存在 4、7、13,它才是一个吉利的数字。
例如 1 => 113 => 11133 => 111733 => 1411733
特别规定,如果最后所有数字都被删掉了,就输出 0
小A觉得这个枯燥的工作不适合他这样的天才, 于是就把这个工作交给了你。
当然, 只要你能顺利解决,小 A 承诺会在那篇将会震惊世界的论文的特别感谢栏
上署上你的大名。
【输入格式】 (kakutani.in)
一共 1  n 行。
第一行一个正整数 ) 0 10 1 (   n n ,表示数字个数。
接下来每行一个正整数 x 。
【输出格式】 (kakutani.out)
一共 n 行。
每行一个正整数,表示输入每个 x 对应的答案。
【输入输出样例】
kakutani.in kakutani.out
5
13713
141713
1333333372589
1411733
2147483647
0
11
3333332589
1
21836
【数据规模约定】
对于 10% 的数据, 2147483647 0   x
对于另外 10% 的数据,给定的数字 x 没有数码 3
对于另外 10% 的数据, 1  n
对于全部的数据, ) 00 10 1 (   n n ,
L
x 10 1   )

这里写图片描述

//写个栈 记录一下就好 我当时竟然傻逼到写 双向链表#include <cstdio>#include <cstring>const int MAXN = 131072;char str[MAXN];int main() {    int n, len, m, top;    freopen("kakutani.in", "r", stdin);    freopen("kakutani.out", "w", stdout);    scanf("%d", &n);    for (; n; n--) {        scanf("%s", str);        len = strlen(str), m = 0, top = 0;        for (int i = 0; i < len; i++)            if (str[i] == '1') top++;            else if (str[i] == '4' || str[i] == '7') continue;            else if (str[i] == '3') {                if (top > 0) top--;                else str[m++] = str[i];            }            else{                for ( ; top > 0; top--) str[m++] = '1';                str[m++] = str[i];            }        for ( ; top > 0; top--) str[m++] = '1';        str[m] = '\0';        if (m == 0) puts("0");        else printf("%s\n", str);    }    fclose(stdin); fclose(stdout);    return 0;}

考场AC代码:

#include <cstdio>#include <iostream>#include <cstring>using namespace std;#define rg register#define Max 100100char str[Max];int nxt[Max], pre[Max];int main (int argc, char *argv[]) {    freopen("kakutani.in","r",stdin);    freopen("kakutani.out","w",stdout);    int N, Len, Count;    scanf ("%d", &N);    rg int i, j;    for(; N ; -- N){        scanf("%s",str + 1);        Len=strlen(str + 1);        nxt[0]=1,Count=Len;        for(i = 1; i <= Len + 1; ++ i) nxt[i]=i + 1,pre[i]=i - 1;        for(i = 1; i <= Len; i = nxt[i])            for (; str[i] == '4' || str[i] == '7' || (str[pre[i]] == '1' && str[i] == '3') || (str[nxt[i]] == '3' && str[i] == '1'); ) {                for(;str[i]=='4';)                    str[i]=str[nxt[i]],nxt[i]=nxt[nxt[i]],pre[nxt[i]]=i,nxt[pre[i]]=i,--Count;                for(;str[i]=='7';)                    str[i]=str[nxt[i]],nxt[i]=nxt[nxt[i]],pre[nxt[i]]=i,nxt[pre[i]]=i,--Count;                for(;str[nxt[i]]=='3'&&str[i]=='1';)                    Count-=2,str[i]=str[pre[i]],pre[i]=pre[pre[i]],nxt[pre[i]]=i,nxt[i]=nxt[nxt[i]],pre[nxt[i]]=i;                for(;str[pre[i]]=='1'&&str[i]=='3';)                    Count-=2,str[i]=str[nxt[i]],nxt[i]=nxt[nxt[i]],pre[nxt[i]]=i,pre[i]=pre[pre[i]],nxt[pre[i]]=i;            }        if(!Count){ puts("0"); continue; }        else for(i=0;i<=Len;i=nxt[i]) if(str[i]!='\0') putchar(str[i]);        putchar ('\n');    }    fclose(stdin);fclose(stdout);    return 0;}

2. 刀塔

(dota.pas/c/cpp)
(dota.in/out)
时间限制:2s/空间限制:256M
【题目描述】
事情要从小 A 的朋友小 S 说起,小 S 是个刀塔狂热粉,他每天除了学习就是
在打刀塔。然而让小 S 很苦恼的事情是,他发现最近他似乎遇见瓶颈了,他发现
他每次输的时候都是雪崩, 赢的时候都是躺赢, 完全发挥不出自己应该有的实力。
他上贴吧请教了三分钟辉耀羊刀的万分大神,接到了万分大神的圣旨:去看自己
的录像反省反省。于是小 S 决定利用十一假期的时间好好反省反省。
小 S 调出了自己前段时间的游戏录像,一共有 N 个录像,他给每个录像一个
正整数表示这个录像的观看价值。 现在他决定从里面找到二组连续的录像来观看,
这两组录像的要求如下:
1.两组录像里每一组的录像数量都不能小于 A,不然没有意义
2.他看的总录象的数量一定要超过 B,他相信看的越多就越好
3.小 S 觉得两组录像时间隔的太近没有意义,因为很有可能前后两段暴露的
问题基本一致,但是他又觉得隔的太远也干扰他去思考自己当时的状态。所以他
要求这两段录像中间应该刚好隔了 K 个录像
好吧,这已经够让人烦躁的了,但是小 S 还不满足,他觉得这样的挑选方案
依旧很多,所以他想挑选足够好的方案,一个质量足够高的方案——也就是观看
价值最低的录像的观看价值要尽可能的高。
【输入格式】 (dota.in)
一共 2 行。
第一行四个正整数 K B A N 、 、 、 。
接下来一行 N 个正整数,表示每个录像的观看价值 ) 10 1 (
9
  x x 。
【输出格式】 (dota.out)
一共 1 行,表示最佳方案中观看价值最低的录像的观看价值。
【输入输出样例 1】
dota.in dota.out
10 2 5 3
7 8 2 3 1 6 4 10 5 9
4
【输入输出样例 2】
dota.in dota.out
20 3 9 3
54867025 259306632 473619223 170507035
347936959 421059860 246006182 948910354
630205869 541359081 574152766 665959900
843439075 445125437 774018043 719562887
705993886 133173428 256457367 708196876
246006182
【数据规模约定】
这里写图片描述

//二分答案#include <cstdio>#include <algorithm>using namespace std;const int MAXN = 2097152;int N, A, B, K;int x[MAXN];int l[MAXN], r[MAXN];bool check(int c) {    for (int i = 1; i <= N; i++)        if (x[i] >= c) l[i] = l[i - 1] + 1;        else l[i] = 0;    for (int i = N; i >= 1; i--)        if (x[i] >= c) r[i] = r[i + 1] + 1;        else r[i] = 0;    for (int i = 1; i <= N; i++)        if (l[i - 1] >= A && r[i + K] >= A && l[i - 1] + r[i + K] >= B)            return true;    return false;}inline void read(int &x){    x=0; int f=1; register char c=getchar();    while(c>'9'||c<'0'){ if(c=='-')f=-1; c=getchar(); }    while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;}int main() {    freopen("dota.in", "r", stdin);    freopen("dota.out", "w", stdout);    int left = 99999999, Mid, right = -19999999,Ans;    read(N),read(A),read(B),read(K);    for (int i = 1; i <= N; i++)        read(x[i]), left = min(left, x[i]), right = max(right,x[i]);    --left, ++right;    while (left <= right) {        Mid = (left + right) >> 1;        if (check(Mid)) left = Mid + 1 ,Ans = Mid;        else right = Mid - 1;    }    printf("%d\n", Ans);    return 0;}

3. 反击数

(spenum.pas/c/cpp)
(spenum.in/out)
时间限制:2s/空间限制:256MB
【题目描述】
上次说到小 A 在你的帮助下,在反证角谷猜想的路上已经看见了曙光,他相
信自己即将为这个著名难题画上最后的句点,小 A 十分地兴奋,结果他那微不足
道的老毛病又犯了——他忍不住想炫耀一番,结果搞得朋友圈内人尽皆知,当然
也就传到了另一位学霸小 H 的耳中。
虽然表面上小 H 和小 A 是挚友,但其实不难想象,这两个天才在私下里早已
将对方视为此生必须要战胜的对手。和天赋异禀的小 A 不同,小 H 拥有的是逆天
的气运——经常他选择题都不需要看选项就能全对 (据说这也是曾经笃信唯物主
义的小 A 为什么变得神经质般迷信的根本原因) 现在小 H 要正式向小 A 在角谷猜
想上发起反击, 不过两个学霸在某一点上倒是达成了一致——这个猜想一定是错
的,所以它必然有反例!
对自己的气运抱有足够自信的小 H 打算用这样的方式来找到反例:他先选定
一个自己的幸运数 X,他认为所有中间出现了 X 的数都是“扩展幸运数” (包括
X 自身) (例:若 X=69 那么 84576901 就是一个“扩展幸运数” ,在 84576 后面
出现了数码 69,而 679 则不是一个“扩展幸运数” ),然后小 H 会再精心挑选一
个“命运数”K,最后小 H 将在随机生成的正整数区间[L, R]中选择第 K 大的“扩
展幸运数” ,用它去验证角谷猜想。小 H 认为这样的速度一定快过小 A 那个落后
的办法。
好了,现在同样的工作摆在了你的面前,你需要帮助小 H 得到那个数字。
PS:小 H 有时候会突然无征兆地打瞌睡(为了保养他的运气) ,所以可能正
整数区间[L, R]中并没有 K 个“扩展幸运数” ,这时候输出“Hey,wake up!” (不
含引号)
【输入格式】 (spenum.in)
输入仅有一行,共 4 个数字,按次序分别为 L,R,X,K
【输出格式】 (spenum.out)
输出为一行,即正整数区间[L, R]中第 K 大的“扩展幸运数”
【输入输出样例 1】
spenum.in spenum.out
1 1000 6 14 67
【输入输出样例 2】
spenum.in spenum.out
1 1 2 1 Hey,wake up!
【样例解释】
前 14 个数字分别是 6、16、26、36、46、56、60、61、62、63、64、65、66、67
【数据规模约定】
对于 10% 的数据 : 1000000 1    L R
对于另外 10% 的数据 : 1  K
这里写图片描述

T3 抄的题解。。

#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;typedef unsigned long long ULL;char p[32];int m,nxt[32];void KMP(){    nxt[0] = 0,nxt[1] = 0;    for(int i=1; i<m; ++i){        int j = nxt[i];        while(j && p[i]!=p[j]) j = nxt[j];        nxt[i + 1] = p[i] == p[j] ? j + 1 : 0;    }}int a[32];ULL dp[20][2000][2];ULL DFS(int k,int w,bool lim, bool get) {    if(!k) return get;    else if(!lim && ~dp[k][w][get]) return dp[k][w][get];    else {        ULL ret = 0;        for (int i = 0, j = lim ? a[k] : 9; i <= j; i++) {            int t = w;            while (t && p[t] - '0' != i) t = nxt[t];            if (p[t] - '0' == i) t++;            ret += DFS(k - 1, t, lim && (i == a[k]), get || (t == m));        }        return lim ? ret : dp[k][w][get] = ret;    }}ULL query(ULL x){    int top = 0;    while(x) {        a[++top] = x % 10;        x /= 10;    }    memset(dp,0xff,sizeof dp );    return DFS(top,0,true,false);}int main(int argc,char *argv[]){    freopen("spenum.in", "r", stdin);    freopen("spenum.out", "w", stdout);    ULL L,R,K;    scanf("%I64u %I64u %s %I64u",&L,&R,p,&K);    m = strlen(p);    KMP();    K += query(L - 1);    if (query(R - 1) < K ) {        puts("Hey,wake up!");        return 0;    }    ULL tmp = 1 ,Ans = L - 1;    while(tmp < R - L + 1) tmp <<= 1;    while(tmp){        if(query(Ans + tmp) < K) Ans += tmp;        tmp >>= 1;    }    printf("%I64u",Ans + 1);    return 0;}
原创粉丝点击