190504--2019湘潭大学程序设计大赛重现赛

发现自己真的太菜了,签到题全部wa,所以现根据网上题解和自己的理解做一个题解自己看看
再此顺便感谢网上贴出题解供我理解的大佬们:
阿茶家的庸医(注释和方法都非常清晰!!!)
yjun
守林鸟
ccsu_YangJ

目录

A.Who's matter?(签到题)
B.Number(签到题)
C.Math Problem(签到题)
D.stone(签到题)
F.Black & White


链接:https://ac.nowcoder.com/acm/contest/893/A
来源:牛客网

A.Who's matter?(签到题)

ICPC比赛中,谁通过的题数多,谁排名靠前;在通过题数相同的情况下,谁的罚时少,谁排名靠前;如果前两者都相同,就看最后正确提交的时间,谁早最排名靠前。 现在给你两个队伍的正确通过的题数、罚时和最后正确提交时间,请判断一下,谁的排名更靠前?

输入描述:

只有一组测试样例,两行,每行三个整数n(0≤n≤13),p(1≤p≤1000),s(1≤s≤300),依次表示两个队的正确通过的题数、罚时和最后正确提交时间。

输出描述:

输出一行(末尾要换行符)。
如果是第1个队排名靠前,输出1;如果是2队,输出2;如果无法分辨,输出"God"。

1 10 10
1 22 2

输出

<pre>1</pre>

示例2

输入

<pre>1 10 10
2 42 20</pre>

输出

<pre>2</pre>

示例3

输入

1 10 10
1 10 10

输出

God

//注意不要超时
#include<stdio.h>
#include<iostream>
using namespace std;
int main(){
    int a,b,suma=0,sumb=0,ta,tb,sa,sb;
    scanf("%d%d%d",&a,&ta,&sa);
    scanf("%d%d%d",&b,&tb,&sb);
    if(a>b)suma++;
    else if(b>a)sumb++;
    else {
        if(ta<tb)suma++;
        else if(ta>tb)sumb++;
        else {
           if(sa>sb)sumb++;
           else if(sa<sb)suma++;

        }
        
    }
    if(suma>sumb)cout<<"1"<<endl;
    else if(suma<sumb)cout<<"2"<<endl;
    else cout<<"God"<<endl;
    return 0;
}


链接:https://ac.nowcoder.com/acm/contest/893/B
来源:牛客网

B.Number(签到题)

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

Bonnie得到了一个数字n。
现在她想对这个数字不断的做一种操作:

  • 如果n的最后一位数码是0,那么她就把n除以10;
  • 否则她把这个数加上1;
  • 直到n变为一个不大于1的数。

给定n,请问Bonnie需要做多少次操作?

输入描述:

<pre>第一行一个数字T(1≤T≤300000)-样例个数。

每个样例仅一行一个数字n(1≤n≤109)

输出描述:

每个样例输出一行一个数字—Bonnie需要做的操作次数。

示例1

输入

6
9
99
2
11032
1000000000
62

输出

2
3
9
44
9
13

说明

<pre>第一个样例: 9→10→1
第二个样例: 99→100→10→1

//做不出纯粹是我个人理解题目的问题
//我以为判断条件是转化成二进制码的最后一位,没想到n%10暴力AC,orz
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
int main(){
    int n,count,t;
    scanf("%d",&t);
    while(t--){
        count=0;
        scanf("%d",&n);
        while(n>1){
        if(n%10==0)n=n/10;
        else n++;
        count++;
        };
       cout<<count<<endl;   
    }
        return 0;
}


链接:https://ac.nowcoder.com/acm/contest/893/C
来源:牛客网

C.Math Problem(签到题)

题目描述

已知整数a,a3,a,a^3除192的余数是1。求区间[L,R]之间满足条件的a的累加和是多少?

输入描述:

<pre>第一行是一个整数T(1≤T≤10000)表示样例的个数。
每个样例包含两个整数L,R,1≤L≤R≤109

输出描述:

每行输出一个样例的结果。

示例1

输入

1
1 10

输出

1
超时代码:

#include<stdio.h>
#include<iostream>
#define ll long long 
using namespace std;
ll f(ll l,ll r){
    ll sum=0;
    for(int i=l;i<=r;i++){
       ll m=i*i*i;
        if(m%192==1)
         sum+=i;   
    }
    return sum;
}
int main(){
    ll t,l,r,a;
    cin>>t;
    while(t--){
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",f(l,r));
    }
}

AC代码1:找规律,复杂度减少
(ak+1)3=a3k3+3a2k2+3ak+1=(a2k3+3a1k^2+3k)a+1=a*x+1;

即(a*k+1)的3次方也是a的倍数+1;

#include<bits/stdc++.h>
using namespace std;
int t,l,r;

int main(){
   
    
    scanf("%d",&t);
    while(t--){
        long long ans=0;
        scanf("%d%d",&l,&r);
        int p=l/192,q=r/192;
        if(l%192>1)p++;
        if(r%192<1)q--;
        for(int i=p;i<=q;i++){
            ans=ans+(long long )i*192+1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

AC代码2:

#include<stdio.h>
#include<iostream>
#define inf 0x3f3f3f3f
#define ll long long 
using namespace std;
int t;
ll l,r,a;
ll f(ll l,ll r){
    ll sum=0;
    while(l%192!=1)
        l++;
    while(r%192!=1)
        r--;
    a=r/192-l/192+1;
    sum=((l+r)/2)*a;
    return sum;
}
int main(){
    cin>>t;
    while(t--){
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",f(l,r));
    }
}


链接:https://ac.nowcoder.com/acm/contest/893/D
来源:牛客网

D.stone(签到题)

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述[](javascript:void(0);)[]

有n堆石子排成一排,第i堆石子有a个石子。
每次,你可以选择任意相邻的两堆石子进行合并,合并后的石子数量为两堆石子的和,消耗的体力等价于两堆石子中石子数少的那个。
请问,将所有的石子合并成一堆,你所消耗的体力最小是多少?

输入描述:

第一行是一个整数T表示样例的个数。
每个样例的第一行是一个整数表示石子堆的数量。
第二行是n个整数ai(1≤ai≤109)

输出描述:

每行输出一个样例的结果。

示例1

输入

2
2
1 2
1
1

输出

1
0

说明

巨大的输入,请使用C风格的输入。

//两两求最大值,然后用总数减最大值
//  WA理由:long long必须用在n,a上
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
#include<queue>
#include<stdlib.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
int main(){
    ll t,n;
    ll a[100000];
    scanf("%d",&t);
    while(t--){
        ll sum=0;
        scanf("%d",&n);
        ll Max=0;
        for(int i=0;i<n;i++){
           scanf("%lld",&a[i]);
            sum+=a[i];
           Max=max(Max,a[i]);
           
        }
        printf("%lld\n",sum-Max);
    }
    return 0;
}


F.Black & White

题目描述

你有一个长度为 n 的 01 串S,你可以执行最多 m 次操作。
对于每次操作,你可以选择一个位置 i 满足
1≤i≤n,翻转这一位的值,0变成1,1变成0。
定义一个 01 串的价值为其中最长连续0的个数和最长连续1的个数的较大值,求S在经过最多m次操作后的最大价值。

输入描述:

第一行一个整数 T ,表示接下来有 T 个样例。
首先输入n,m,表示S串的长度n和操作次数m,其中
1≤n≤100000,0≤m≤10000;
接下来输入一个长度为n的字符串S。

输出描述:

一个整数,表示题面上描述的最大价值。
示例1

输入

2
5 1
00101
2 1
01

输出

4
2

说明

第一个串翻转第三个位置,00001的价值为4;第二个串翻转第一个位置,11的价值为2。

思路:

  • 尺取法(目前还搞不太清楚,故贴出大佬的尺取法的学习地址:尺取法 — 详解 + 例题模板(全)
  • 前缀+二分法:
    首先预处理两个数组 pre1 和 pre0,分别代表1~i个位置上1和0的个数
    这样就可以在 O(1) 的时间求出 区间内 1或者0 的个数
    然后二分答案:最大长度len。
    因为 len 是固定的,所以 l=1,r=len 开始 滑动窗口(时间O(n)),每次移动都判断当前方块内 1或者0的个数是否小于 可以改变的次数m,如果小于等于 则 len 可以成立,可以往更大值二分,否则只能往更小值二分。
    时间复杂度:每次二分判断需要O(n)的时间,二分需要log2(n)的时间,所以总时间n*lg(n)时间复杂度ok

贴出前缀+二分AC代码:

//大佬(阿茶的庸医)的代码
#include <iostream>
#include <algorithm>
#include <string>
#define N 100010
using namespace std;
string str;
int n, m;
int pre0[N], pre1[N];//0和1的个数数组
//判断是否可以进行转换
//(每次移动都判断当前方块内 1或者0的个数是否小于 可以改变的次数m)
bool judjed(int len){
    int l = 1, r = len;
    while(r <= n){
        if(pre0[r]-pre0[l-1] <= m || pre1[r]-pre1[l-1] <= m)
            return true;
        ++l, ++r;
    }
    return false;
}
//二分
int get_n(){
    int res;
    int l=0, r=n;
    while(l <= r){
        int mid = (l+r)/2;
        if(judjed(mid)){//可以往更大值二分
            l = mid+1;
            res = mid;
        }else{
            r = mid-1;
        }
    }
    return res;   
}

int main(){
    int T;
    cin >> T;
    while(T--){
        cin >> n >> m;//n长度,m操作次数
        cin >> str;
        for(int i=1; i<=n; i++){
            if(str[i-1] == '0'){
                pre0[i] = pre0[i-1]+1;
                pre1[i] = pre1[i-1];
            }else{
                pre0[i] = pre0[i-1];
                pre1[i] = pre1[i-1]+1;
            }
        }
        cout << get_n() << endl;
        str.clear();
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342