湖南师范大学2021年3月25日蓝桥杯热身赛解题报告与标程

A

题目描述

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

寛神去鹅厂做项目经理去了,他带领3个开发组。工期紧,今天都在加班呢。为鼓舞士气,他打算给每个组发一袋核桃(据传言能补脑)。他的要求是:

各组的核桃数量必须相同
各组内必须能平分核桃(当然是不能打碎的)
尽量提供满足1,2条件的最小数量(节约闹革命嘛)

解法

很明显求gcd

标程

from math import *

if __name__ == '__main__':
    a, b, c = [int(i) for i in input().split()]
    tmp = a * b // gcd(a, b);
    print(tmp * c // gcd(tmp, c))
#include <bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t unordered_map

char *__abc147, *__xyz258, __ma369[100000];
#define __hv007() ((__abc147==__xyz258) && (__xyz258=(__abc147=__ma369)+fread(__ma369,1,100000,stdin),__abc147==__xyz258) ? EOF : *__abc147++)

int getUnsigned(){
	char ch = __hv007();
	while( ch < '0' || ch > '9' ) ch = __hv007();

	int ret = (int)(ch-'0');
	while( '0' <= ( ch = __hv007() ) && ch <= '9' ) ret = (ret<<1) + (ret<<3) + (int)(ch-'0');
	return ret;
}

typedef int llt;
llt gcd(llt a,llt b){
    while( b ){
        llt r = b;
        b = a % b;
        a = r;
    }
    return a;
}

llt solute(int a,int b, int c){
	int tmp = a/gcd(a,b)*b;
	return tmp*c/(gcd(tmp,c));
}

int main(){
    // freopen("1.txt","r",stdin);
    // freopen("2.txt","w",stdout);
	int a = getUnsigned();
	int b = getUnsigned();
	int c = getUnsigned();
	int tmp = a/gcd(a,b)*b;
	printf("%d\n",solute(a,b,c));
    return 0;
}

B

题目描述

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

寛神在鹅厂赚了钱,买了个植物园。
这个植物园被分成m * n 个小格子(东西方向m行,南北方向n列)。每个格子里种了一株合根植物。
这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。
寛神想知道这个园子中一共有多少株植物。显然合根植物只算一株。

解法

并查集,或者深搜也可以。

标程

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

#define fi first
#define se second
typedef pair<int,int> pii;

struct ufs_t{
    enum{UF_SIZE=1000010};
    int father[UF_SIZE+1];
    
    void init(int n){for(int i=0;i<=n;++i)father[i]=i;}
    int find(int x){return father[x]==x?x:father[x]=find(father[x]);}
    void unite(int x,int y){father[find(y)]=find(x);}
}UF;

typedef pair<int,int> pii;
pii A[ufs_t::UF_SIZE];
int solute(int n,int m, int k,pii a[]){
	UF.init(n*m);
	for(int i=0;i<k;++i){
		UF.unite(a[i].fi,a[i].se);
	}
	int ans = 0;
	for(int s=n*m,i=1;i<=s;++i)if(UF.find(i)==i)++ans;
	return ans;
}

int main(){
    int m,n;
    scanf("%d%d",&m,&n);
    UF.init(m*n);
    int k;
    scanf("%d",&k);
    while(k--){
        int a,b;
        scanf("%d%d",&a,&b);
        UF.unite(a, b);
    }
    int ans = 0;
    for(int s=m*n,i=1;i<=s;++i)if(UF.find(i)==i)++ans;
    printf("%d\n",ans);
    return 0;
}

C

题目描述

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

寛神去鹅厂打工有钱了,决定下学期每天都请419吃饭。吃饭当然是要开发票的,为国家税收做贡献。

每张发票有唯一的ID号。所有票据的ID号是连续的,因为每天都要请吃饭。但ID的开始数码不一定的,因为下学期不知道什么时候开始。

因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。

你的任务是通过编程,找出断号的ID和重号的ID。

假设断号不可能发生在最大和最小号。

解法

因为最大的数值不会超过 100 , 000 100,000 100,000,用标记数组记录即可。
这道题最麻烦的是处理输入。使用python或者java会简单一些。C/C++中使用 s t r t o k strtok strtok比较方便。当然C++中还可以使用 s t r i n g s t r e a m stringstream stringstream也可以,或者直接使用 c i n cin cin,数据不大,应该不会超时。

标程

import sys
sys.setrecursionlimit(10 ** 6)

def solute():  
    n = int(input())
    a = []
    for i in range(n):
        a.extend([int(i) for i in input().split()])
    b = [False for i in range(100010)]
    chong, duan = -1, -1
    for ai in a:
        if b[ai]: chong = ai
        else: b[ai] = True
    start = min(a)
    while b[start]: start += 1
    duan = start
    print(duan, chong)
    return duan, chong

if __name__ == '__main__':
    solute()
/**
    给若干行,每行若干数,且有不定数量的空格
    这些数保证是连续的,其中只有一个是重复的,且只有一个是漏掉的
    找到这两个数
*/
#include <bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t unordered_map


char A[1000010];
bool Flag[100010] = {false};

inline bool isEmpty(){
    for(char const*p=A;*p;++p){
        if(isdigit(*p)) return false;
    }    
    return true;
}

int main(){
    // freopen("1.txt","r",stdin);
    // freopen("2.txt","w",stdout);
    int n,m;
    scanf("%d",&n);
    fgets(A,1000000,stdin);

    char const delim[] = " ";

    int chong, duan = 100000000;
    while(n--){
        fgets(A,1000000,stdin);

        if(isEmpty()) continue;
        
        char *p = strtok(A, delim);
        while(p!=NULL){
            sscanf(p,"%d",&m);
            if(Flag[m]) chong = m;
            else Flag[m] = true;
            duan = min(duan, m);
            p = strtok(NULL, delim);
        }
    }

    while(Flag[duan]) ++duan;

    printf("%d %d\n",duan, chong);
    
    return 0;
}

D

题目描述

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

寛神有一堆的幸运数,因为他非常善于学习,只要听到有人用哪个数做幸运数,就会把这个数加到自己的幸运数集合。
直到有一天他听说了波兰数学家乌拉姆的幸运数。它采用与生成素数类似的“筛法”生成。
首先从1开始写出自然数1,2,3,4,5,6,…
1就是第一个幸运数。
我们从2这个数开始。把所有序号能被2整除的项删除,变为:
1 _ 3 _ 5 _ 7 _ 9 …
把它们缩紧,重新记序,为:
1 3 5 7 9 …。这时,3为第2个幸运数,然后把所有能被3整除的序号位置的数删去。注意,是序号位置,不是那个数本身能否被3整除!!删除的应该是5,11, 17, …
此时7为第3个幸运数,然后再删去序号位置能被7整除的(19,39,…)
最后剩下的序列类似:
1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, …

解法

这个题目比较坑爹,题面说规模为 1 , 000 , 000 1,000,000 1,000,000,实际上数据集不超过 15 , 000 15,000 15,000。大规模的话需要用堆来做,应该是 N l o g ( N ) Nlog(N) Nlog(N)。小规模当然是打表啦。

标程

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

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t unordered_map

int const G[]={1,3,7,9,13,15,21,25,31,33,37,43,49,51,63,67,69,73,75,79,87,93,99,105,111,115,127,129,133,135,141,151,159,163,169,171,189,193,195,201,205,211,219,223,231,235,237,241,259,261,267,273,283,285,289,297,303,307,319,321,327,331,339,349,357,361,367,385,391,393,399,409,415,421,427,429,433,451,463,475,477,483,487,489,495,511,517,519,529,535,537,541,553,559,577,579,583,591,601,613,615,619,621,631,639,643,645,651,655,673,679,685,693,699,717,723,727,729,735,739,741,745,769,777,781,787,801,805,819,823,831,841,855,867,873,883,885,895,897,903,925,927,931,933,937,957,961,975,979,981,991,993,997,1009,1011,1021,1023,1029,1039,1041,1053,1057,1087,1093,1095,1101,1105,1107,1117,1123,1147,1155,1167,1179,1183,1189,1197,1201,1203,1209,1219,1231,1233,1245,1249,1251,1261,1263,1275,1281,1285,1291,1303,1309,1323,1329,1339,1357,1365,1369,1387,1389,1395,1401,1417,1419,1435,1441,1455,1459,1471,1473,1485,1491,1495,1497,1501,1503,1519,1533,1543,1545,1563,1567,1575,1579,1585,1587,1597,1599,1611,1639,1641,1645,1659,1663,1675,1693,1701,1705,1711,1723,1731,1737,1749,1765,1767,1771,1773,1777,1797,1801,1809,1819,1827,1831,1833,1839,1857,1869,1879,1893,1899,1915,1921,1923,1933,1941,1945,1959,1963,1965,1977,1983,1987,1995,2001,2019,2023,2031,2053,2059,2065,2067,2079,2083,2085,2095,2113,2115,2121,2125,2127,2133,2163,2173,2187,2209,2211,2215,2217,2221,2239,2251,2253,2257,2271,2277,2281,2283,2301,2311,2317,2323,2335,2343,2355,2365,2379,2395,2403,2407,2409,2415,2419,2427,2439,2445,2461,2467,2473,2479,2491,2493,2505,2511,2523,2527,2545,2557,2563,2571,2575,2587,2589,2593,2599,2607,2625,2635,2647,2649,2653,2661,2667,2671,2689,2697,2715,2725,2755,2763,2773,2781,2785,2787,2797,2815,2817,2821,2823,2827,2835,2841,2845,2851,2877,2887,2899,2901,2905,2913,2923,2943,2953,2961,2971,2973,2977,2983,3003,3007,3027,3031,3037,3039,3049,3055,3073,3075,3091,3097,3099,3109,3111,3121,3123,3133,3153,3163,3171,3175,3183,3187,3199,3213,3223,3229,3235,3243,3259,3261,3289,3297,3301,3307,3313,3325,3339,3351,3355,3363,3381,3403,3405,3409,3411,3427,3433,3439,3451,3453,3465,3477,3481,3487,3489,3495,3499,3507,3559,3565,3571,3579,3595,3597,3603,3607,3613,3621,3625,3633,3655,3661,3663,3669,3675,3685,3687,3697,3709,3717,3721,3727,3747,3753,3763,3771,3781,3789,3793,3795,3811,3843,3847,3849,3865,3873,3879,3889,3891,3897,3909,3915,3931,3943,3951,3955,3969,3975,3981,3991,3999,4003,4015,4023,4033,4035,4041,4045,4063,4069,4081,4095,4105,4107,4129,4131,4161,4165,4173,4179,4189,4195,4201,4203,4207,4227,4237,4251,4255,4257,4263,4269,4285,4287,4315,4321,4329,4335,4363,4377,4383,4389,4399,4413,4431,4441,4443,4455,4461,4465,4483,4485,4495,4509,4519,4521,4539,4551,4561,4567,4569,4573,4587,4609,4611,4621,4623,4629,4645,4647,4653,4663,4671,4675,4695,4699,4713,4717,4725,4741,4761,4767,4773,4797,4801,4809,4813,4819,4833,4837,4839,4843,4851,4863,4867,4881,4887,4893,4929,4951,4963,4965,4969,4977,4987,4989,4993,4999,5001,5007,5019,5029,5041,5043,5049,5053,5089,5103,5127,5137,5139,5149,5151,5157,5169,5179,5181,5191,5211,5217,5229,5233,5235,5253,5259,5277,5283,5293,5295,5299,5325,5335,5341,5343,5371,5377,5379,5385,5409,5419,5427,5433,5449,5455,5463,5473,5487,5491,5503,5515,5527,5547,5551,5559,5569,5577,5587,5589,5593,5599,5613,5617,5637,5641,5649,5655,5661,5671,5673,5679,5691,5701,5707,5713,5719,5737,5755,5763,5767,5769,5803,5809,5817,5827,5833,5839,5851,5869,5883,5889,5893,5901,5905,5911,5913,5923,5959,5965,5967,5971,5973,5977,5991,5997,6009,6019,6031,6049,6055,6061,6079,6093,6111,6115,6123,6141,6147,6159,6163,6175,6177,6195,6211,6229,6237,6243,6249,6253,6271,6273,6279,6301,6309,6331,6345,6351,6355,6363,6367,6369,6373,6379,6385,6399,6411,6415,6427,6433,6435,6447,6463,6471,6475,6477,6501,6505,6523,6531,6535,6541,6553,6559,6567,6573,6601,6621,6625,6631,6661,6663,6667,6669,6679,6687,6693,6715,6723,6733,6741,6745,6747,6753,6757,6763,6765,6783,6787,6789,6841,6849,6867,6871,6883,6891,6909,6915,6921,6931,6933,6937,6951,6981,6985,6999,7003,7009,7035,7041,7045,7047,7069,7077,7081,7087,7101,7111,7129,7135,7153,7167,7171,7173,7183,7191,7195,7197,7207,7215,7231,7233,7237,7245,7249,7279,7293,7299,7311,7321,7333,7339,7341,7345,7357,7359,7371,7377,7395,7401,7405,7419,7435,7437,7443,7447,7459,7471,7489,7501,7503,7507,7531,7533,7549,7551,7563,7567,7575,7585,7591,7593,7603,7609,7629,7633,7639,7645,7677,7687,7689,7701,7711,7717,7737,7755,7779,7791,7795,7801,7803,7813,7827,7833,7837,7855,7881,7885,7897,7899,7909,7917,7921,7929,7939,7947,7951,7963,7969,7971,8001,8005,8007,8013,8037,8047,8071,8073,8085,8089,8107,8109,8127,8131,8139,8151,8161,8169,8173,8175,8191,8193,8221,8223,8227,8233,8253,8257,8263,8269,8283,8289,8299,8325,8331,8347,8359,8365,8367,8379,8409,8413,8421,8445,8449,8467,8473,8475,8479,8487,8493,8515,8535,8539,8551,8553,8575,8577,8583,8589,8601,8605,8611,8617,8635,8637,8641,8647,8655,8661,8673,8683,8719,8757,8769,8773,8787,8793,8805,8809,8827,8829,8833,8835,8841,8869,8871,8895,8913,8931,8937,8947,8955,8961,8977,8979,8989,8995,8997,9009,9031,9033,9061,9063,9073,9075,9081,9085,9115,9117,9121,9123,9135,9139,9145,9151,9177,9181,9211,9213,9223,9231,9235,9249,9253,9267,9273,9277,9285,9291,9303,9315,9331,9339,9349,9373,9387,9399,9403,9409,9421,9423,9429,9441,9451,9457,9471,9475,9481,9483,9487,9501,9535,9537,9543,9547,9549,9555,9561,9567,9613,9621,9625,9631,9643,9649,9661,9663,9675,9687,9691,9703,9727,9733,9751,9753,9775,9787,9789,9795,9801,9807,9811,9813,9837,9841,9883,9895,9915,9927,9937,9957,9961,9979,9985,9987,9997,9999,10003,10009,10017,10041,10051,10059,10069,10071,10083,10087,10089,10095,10111,10117,10125,10131,10143,10147,10149,10153,10173,10191,10195,10197,10221,10239,10255,10261,10275,10279,10291,10311,10315,10317,10321,10341,10363,10365,10387,10399,10411,10417,10431,10441,10443,10459,10461,10471,10501,10507,10509,10525,10531,10533,10555,10563,10569,10575,10585,10587,10597,10599,10605,10609,10635,10651,10653,10659,10671,10683,10723,10725,10731,10747,10753,10755,10759,10773,10785,10789,10797,10809,10843,10849,10873,10881,10891,10903,10909,10911,10921,10923,10945,10953,10965,10975,10977,11005,11011,11017,11047,11055,11059,11073,11077,11089,11091,11097,11113,11137,11157,11163,11173,11181,11193,11197,11205,11217,11223,11227,11239,11245,11247,11259,11263,11269,11283,11289,11301,11323,11341,11343,11371,11373,11377,11389,11391,11395,11407,11419,11425,11427,11437,11439,11475,11479,11487,11491,11521,11529,11535,11539,11541,11577,11581,11583,11599,11617,11623,11629,11641,11643,11659,11667,11677,11679,11707,11721,11725,11731,11769,11781,11797,11803,11811,11815,11823,11827,11833,11835,11845,11847,11853,11865,11877,11887,11911,11923,11929,11943,11953,11959,11961,11991,11995,12007,12015,12025,12049,12057,12063,12069,12079,12097,12103,12117,12121,12133,12139,12141,12151,12159,12163,12165,12193,12201,12207,12223,12237,12243,12265,12267,12285,12295,12301,12307,12315,12319,12321,12333,12337,12357,12363,12373,12379,12391,12399,12411,12417,12427,12435,12457,12481,12487,12495,12499,12519,12543,12547,12553,12567,12579,12589,12607,12609,12621,12631,12645,12649,12651,12673,12679,12699,12709,12711,12729,12735,12741,12759,12763,12777,12781,12799,12801,12813,12819,12861,12867,12877,12885,12903,12907,12925,12937,12951,12957,12961,12969,12991,12999,13009,13011,13021,13027,13029,13053,13057,13063,13077,13083,13113,13117,13119,13125,13129,13135,13141,13167,13177,13179,13203,13209,13215,13219,13243,13245,13267,13273,13279,13281,13285,13293,13309,13317,13323,13327,13335,13345,13347,13359,13363,13371,13387,13419,13441,13443,13465,13473,13485,13489,13513,13515,13519,13527,13531,13533,13537,13551,13567,13575,13581,13587,13599,13609,13633,13657,13677,13681,13693,13695,13707,13723,13725,13737,13741,13743,13759,13801,13803,13821,13831,13833,13849,13851,13861,13873,13893,13897,13929,13947,13953,13957,13995,14007,14017,14031,14035,14037,14041,14049,14053,14059,14073,14079,14091,14095,14113,14115,14119,14137,14163,14179,14181,14185,14199,14205,14209,14211,14217,14229,14245,14247,14253,14281,14287,14293,14307,14313,14317,14331,14347,14349,14353,14367,14395,14407,14419,14427,14437,14439,14443,14449,14457,14461,14473,14491,14493,14505,14521,14523,14539,14541,14565,14587,14595,14599,14601,14607,14625,14661,14667,14689,14691,14713,14715,14721,14731,14749,14751,14755,14775,14779,14785,14793,14797,14817,14841,14875,14881,14883,14899,14905,14919,14923,14931,14935,14943,14947,14973,14977,14997};


int const GSIZE = 1599; 

void solute(){
	int a,b;
	scanf("%d%d",&a,&b);
	int const* const ai = upper_bound(G,G+GSIZE,a);
	int const* const bi = lower_bound(G,G+GSIZE,b);
	printf("%d\n",bi-ai);
}

int main(){
    solute();
    return 0;
}


E

题目描述

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

寛神在鹅厂赚了很多钱,决定开个蚁厂。这个厂是线性的。
可以认为整个厂子是一根长100厘米的细长直杆子,上面有n只蚂蚁。它们的头有的朝左,有的朝右。
每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。
当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。
这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。
请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。

解法

可以找规律,然后进行判断。
不过考虑到 n n n x x x都不是很大,也可以写一个模拟。模拟每一秒每一个蚂蚁的位置即可。
考虑到相邻蚂蚁会在坐标 0.5 0.5 0.5处碰面,所以可以把坐标首先都翻倍,然后每 0.5 0.5 0.5秒模拟一次,即可保证正确。

标程

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

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t unordered_map

struct _t{
    int pos; // 位置
    int ori; // 方向
    int bing; //有病
    _t(int a=0,int b=0,int c=0):pos(a),ori(b),bing(c){}
    bool operator < (const _t&rhs){return pos<rhs.pos;}
}A[110];
int const LEFT = 1;
int const RIGHT = 2;

void solute(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;++i){
        scanf("%d",&A[i].pos);
        if(A[i].pos<0){
            A[i].pos = -A[i].pos * 2;
            A[i].ori = LEFT;
        }else{
            A[i].pos <<= 1;
            A[i].ori = RIGHT;
        }
    }
    A[0].bing = 1;
    sort(A,A+n);   

    int s = 0, e = n - 1;
    while(s<n&&(A[s].ori&LEFT)){
        A[s].pos = -100;++s;
    } 
    while(e>=0&&(A[e].ori&RIGHT)){
        A[e].pos = 10000;--e;
    } 

    // typedef vector<int> vi;
    // map<int, vi> posMap;
    // for(int i=s;i<=e;++i)posMap.insert(mp(A[i].pos, vi(1, i)));
    while(s<=e){  // 模拟 
        /// 走1s
        for(int i=s;i<=e;++i){
            if(A[i].ori&LEFT){
                --A[i].pos;      
            }else if(A[i].ori&RIGHT){
                ++A[i].pos;
            }else{
                throw runtime_error("XXXX");
            }
            // printf("(%d %d %d)",A[i].pos,A[i].ori,A[i].bing);
        }
        // printf("[%d %d]\n",s,e);
        /// 检测
        for(int i=s;i<e;++i){
            if(A[i].pos==A[i+1].pos){
                // swap(A[i].ori, A[i+1].ori);
                A[i].ori ^= 3;
                A[i+1].ori ^= 3;
                if(A[i].bing||A[i+1].bing){
                    A[i].bing = A[i+1].bing = 1;
                }
            }        
        }
        while(s<n&&(A[s].ori&LEFT)){
            A[s].pos = -100;++s;
        } 
        while(e>=0&&(A[e].ori&RIGHT)){
            A[e].pos = 10000;--e;
        } 
    }

    int cnt = 0;
    for(int i=0;i<n;++i)if(A[i].bing) ++cnt;
    printf("%d\n",cnt);
}
int main(){
    // freopen("1.txt","r",stdin);
    solute();
    return 0;
}

F

题目描述

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

寛神说从鹅厂回来就请客吃饭,并且给了一个归期。
但是419不知道这个日期的格式。有好几种可能,有年/月/日的,有月/日/年的,还有日/月/年的。更加麻烦的是,年份也都省略了前两位。
比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。

给一个日期,帮419判断出哪天可能有饭吃。

解法

一共就三种情况,挨个判断即可
另外要考虑去重。
原题有一句话,60及其以上的是20世纪,以下的才是21世纪。
这句话忘记拷贝了。所以数据也修正了以下,答案中的年代全部改成了20xx年。

标程

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

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t unordered_map

string int2string(int n){
    stringstream ss;
    ss<<n;
    return ss.str();
}

inline bool isLeaf(int year){
    return 0==year%400||(year%100&&0==year%4);
}

inline bool f(int year,int month, int day){
    if(0==day) return false;
    switch(month){
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:if(day>31) return false;break;
        case 4:
        case 6:
        case 9:
        case 11:if(day>30) return false; break;
        case 2:if(day>28+(isLeaf(year)?1:0))return false;break;
        default:return false;
    }
    return true;
}
inline string get(int year,int month,int day){
    //if(year>=60)year=1900+year;
    //else year=2000+year;
    year += 2000;

    if(f(year,month,day)){
        string ans = int2string(year);
        ans+="-";
        if(month<10) ans += "0";
        ans += int2string(month);
        ans += "-";
        if(day<10) ans += "0";
        ans += int2string(day);
        return ans;
    }
    return "";
}

void solute(){
    int a,b,c;
    scanf("%2d/%2d/%2d",&a,&b,&c);
    vector<string> ans;
    
    string t = get(a,b,c);
    if(!t.empty()) ans.push_back(t);
    
    // t = get(a,c,b);
    // if(!t.empty()) ans.push_back(t);

    // t = get(b,a,c);
    // if(!t.empty()) ans.push_back(t);
    
    // t = get(b,c,a);
    // if(!t.empty()) ans.push_back(t);

    t = get(c,a,b);
    if(!t.empty()) ans.push_back(t);

    t = get(c,b,a);
    if(!t.empty()) ans.push_back(t);

    sort(ans.begin(),ans.end());
    typedef vector<string>::iterator itt;
    itt eit = unique(ans.begin(),ans.end());
    for(itt it=ans.begin();it!=eit;++it)cout<<*it<<endl;
}
int main(){
    // freopen("1.txt","r",stdin);
    solute();
    return 0;
}

G

题目描述

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

寛神到鹅厂打工,跟小马哥谈薪水的问题。
小马哥说这样吧,我左手写一个数,右手写一个数。然后把小钱钱按照这两个数装成两种信封。
不能用这两种信封组合得到的最大钱数就是你的工资。两种信封都是无限多的。
例如一种信封装4元,一种信封装7元,则工资就是17元。因为超过17元都可以用两种信封不同的组合得到。
例如:18元,只要2个7元信封加1个4元信封即可。
资本家当然是非常那啥的,所以保证有有限解。

解法

首先很明显要保证 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1才有有限解,但原题并没有提这件事情。其次, l c m ( a , b ) = a b lcm(a,b)=ab lcm(a,b)=ab以上一定能够组合得到。因为由扩展的欧几里得定理:
a x + b y = 1 ax+by=1 ax+by=1
所以
a b + 1 = a x + b y + a b ab+1=ax+by+ab ab+1=ax+by+ab
所以 a b + 1 ab+1 ab+1一定能够组合得到,而且系数应该是正的。
最后,考虑如果 n n n不能由 a , b a,b a,b组合得到,但是从 n + 1 n+1 n+1 n + a n+a n+a的连续a个数都能由 a , b a,b a,b组合得到,则 n n n就是最大的不能组合得到的数,因为 n + a n+a n+a以上的任何数均可以。所以对 [ 1 , a b ] [1,ab] [1,ab]中所有的数判断其是否能够组合,然后再去找满足上述条件的区间即可,实际上倒着找的第一个不能组合的数即可。
如何判断某个数 n n n是否能够由 a , b a,b a,b组合得到呢。
第一个方法是使用母函数,计算
( 1 + x a + x 2 a + x 3 a + ⋯   ) ( 1 + x b + x 2 b + x 3 b + ⋯   ) (1+x^a+x^{2a}+x^{3a}+\cdots)(1+x^b+x^{2b}+x^{3b}+\cdots) (1+xa+x2a+x3a+)(1+xb+x2b+x3b+)
最高幂次要到 a b ab ab,这个时间复杂度应该是 O ( N 3 ) O(N^3) O(N3)
第二个方法是使用完全背包, 2 2 2种物品,体积最大为 a b ab ab,恰好能装满,时间复杂度应该是 O ( 2 N 2 ) O(2N^2) O(2N2)

以上是判定法。除此之外还有一个方法:

  • 有解的情况下, a , b a,b a,b最大不能组合的数是 a b − a − b ab-a-b abab a , b a,b a,b不能组合的数的数量是 ( a − 1 ) ( b − 1 ) / 2 (a-1)(b-1)/2 (a1)(b1)/2

所以直接算即可,注意要剔除特殊情况, 当 a = 1 或 b = 1 当a=1或b=1 a=1b=1时。

标程

/// 母函数
#include <bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t unordered_map

int const SIZE = 260;
int A[SIZE*SIZE+1],B[SIZE*SIZE+1];
void solute(){
    memset(A,0,sizeof(A));
    memset(B,0,sizeof(B));
    int a,b;
    cin>>a>>b;
    for(int i=0;i<=SIZE*SIZE;i+=a) A[i] = 1;
    for(int i=0;i<=SIZE*SIZE;++i)for(int j=0;j+i<=SIZE*SIZE;j+=b){
        B[i+j] += A[i];
    }
    int ans = SIZE*SIZE;
    while(ans>=0&&B[ans]) --ans;
    printf("%d\n",ans<0?0:ans);
}
int main(){
    // freopen("1.txt","r",stdin);
    solute();
    return 0;
}

// 完全背包
#include <bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t unordered_map

typedef vector<int> vi;
typedef pair<int,int> pii;
typedef vi::const_iterator vcit;
typedef int gains_t;//type of gains

void completeKnapsack(gains_t d[],int maxv,int cost,gains_t gains){
    for(int v=cost;v<=maxv;++v){
		if(d[v-cost]!=-1){
			d[v] = max(d[v],d[v-cost]+gains);
		}        
    }
}

int const SIZE = 251*251;
int D[SIZE];
int main(){
    // freopen("1.txt","r",stdin);
    // freopen("2.txt","w",stdout);
    int a[2];
	scanf("%d%d",a,a+1);
	if(1==a[0]||1==a[1]){
		puts("0");
		return 0;
	}
    memset(D,-1,sizeof(D));
	D[0] = 0;
	int k = a[0]*a[1];
	for(int i=0;i<2;++i){
		completeKnapsack(D,k,a[i],1);
	}
	while(D[k]!=-1) --k;
	printf("%d\n",k);
    return 0;
}

# 直接结论
from math import gcd

a, b = [int(i) for i in input().split()]
print(0 if 1==a or 1==b else a*b//gcd(a,b)-a-b)

H

题目描述

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

寛神在鹅厂打工,除了薪水还有津贴,那是相当的有钱,所以419都嗷嗷待哺。
但是小马哥说寛神是特殊人才,所以要领特殊津贴。
这个津贴是这样算出来的。
给一个数字三角形,从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,这个和就是津贴数。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过1。
寛神毫不犹豫的就找到了最大数,唯一的问题是他不能碰键盘。所以你要帮他打一个程序出来。

解法

很明显DP。
D i , j , k D_{i,j,k} Di,j,k是从位置 ( i , j ) (i,j) (i,j)走到底且左右之差恰好为 k k k能够得到的最大和。
三重循环即可。当然原始的差有可能为负数,所以加一个100。
要注意边界条件。
最早没有注意边界,所以数据有部分是错的,后来修正了。

标程

//暂空

I

题目描述

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

寛神有一个习惯,打键盘的时候必然要对称。因此总是打出诸如12321,123321等回文数字。
所以队友们都不让他碰键盘,于是他就出去打工了。
虽然不能碰键盘,但是他的脑瓜子还是很快的,可以轻松的脑补出各种回文数。
于是他经常上班摸鱼,想象找到一些5位或6位的十进制数字。满足如下要求:
该数字的各个数位之和等于输入的整数。

解法

打表,老年人最爱。

标程

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

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t map

typedef vector<int> vi;
hash_t<int,vi> Map;
hash_t<int,vi>::iterator It;
void solute(){
    if(Map.empty()){
        // 五位回文数
        for(int a=1;a<=9;++a){
            for(int b=0;b<=9;++b){
                for(int c=0;c<=9;++c){
                    int s = a+a+b+b+c, v = a*10001 + b*1010 + c*100;
                    if((It=Map.find(s))==Map.end()){
                        Map.insert(mp(s, vi(1,v)));
                    }else{
                        It->se.pb(v);
                    }
                }
            }
        }
        // 六位
        for(int a=1;a<=9;++a){
            for(int b=0;b<=9;++b){
                for(int c=0;c<=9;++c){
                    int s = a+a+b+b+c+c, v = a*100001 + b*10010 + c*1100;
                    if((It=Map.find(s))==Map.end()){
                        Map.insert(mp(s, vi(1,v)));
                    }else{
                        It->se.pb(v);
                    }
                }
            }
        }
    }
    int n;
    scanf("%d",&n);
    It = Map.find(n);
    if(It==Map.end()){
        puts("-1");return;
    }
    for(vi::iterator it=It->se.begin(),eit=It->se.end();it!=eit;++it){
        printf("%d\n",*it);
    }
}
int main(){
    // freopen("1.txt","r",stdin);
    solute();
    return 0;
}

J

题目描述

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

寛神最擅长图论,他在去鹅厂打工之前决定把毕生功力传给你,如果你能够通过他的考验的话。

419实验室有N台电脑,编号1~N。原本这N台电脑之间有N-1条数据链接相连,恰好构成一个树形网络。在树形网络上,任意两台电脑之间有唯一的路径相连。
不过在最近一次维护网络时,寛神敲错了键盘使得某两台电脑之间增加了一条数据链接,于是网络中出现了环路。环路上的电脑由于两两之间不再是只有一条路径,使得这些电脑上的数据传输出现了BUG。
这就是寛神对你的考验,如果你能够找出有问题的电脑。

解法

T a r j a n Tarjan Tarjan算法找边双连通分量,直接可以出结果。
或者深搜( T a r j a n Tarjan Tarjan本来也就是深搜)。
来回几次,总能出答案。

标程

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

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t unordered_map

typedef vector<int> vi;
typedef pair<int,int> pii;
typedef vi::const_iterator vcit;

int const SIZE = 100010;
vi G[SIZE];
bool Flag[SIZE] = {false};
bool Stop = false;
pii UV;
void dfs_1(int u,int p){
	Flag[u] = true;
	const vi&v = G[u];
	for(vcit it=v.begin();it!=v.end();++it){
		if(*it==p)continue;
		if(Flag[*it]){
			UV.fi = u;
			UV.se = *it;
			Stop = true;
			break;
		}
		dfs_1(*it, u);
		if(Stop) break;
	}
}
int Path[SIZE] = {0};
void dfs_2(int u,int p){
	Flag[u] = true;
	const vi&v = G[u];
	for(vcit it=v.begin();it!=v.end();++it){
		if(*it==p)continue;
		if(u==UV.fi&&*it==UV.se||(u==UV.se&&*it==UV.fi))continue;
		Path[*it] = u;
		dfs_2(*it, u);
	}	
}
int main(){
    // freopen("1.txt","r",stdin);
    // freopen("2.txt","w",stdout);
    int n;
	scanf("%d",&n);
	for(int a,b,i=0;i<n;++i){
		scanf("%d%d",&a,&b);
		G[a].pb(b);G[b].pb(a);
	}
	if(1==n) {
		printf("1\n");
		return 0;
	}
	dfs_1(1, 0); // 找环上的一条边
	int a = UV.fi, b = UV.se;
	int t = count(G[a].begin(),G[a].end(),b);
	if(2==t){
		printf("%d %d\n",min(a,b),max(a,b));
		return 0;
	}
	// G[a].erase(find(G[a].begin(),G[a].end(),b));
	// G[b].erase(find(G[b].begin(),G[b].end(),a));
	// for(auto i:G[a])printf("%d ",i);puts("");
	// for(auto i:G[b])printf("%d ",i);puts("");
	Stop = false;
	fill(Flag,Flag+n+1,false);
	dfs_2(a, b); // 找环
	fill(Flag,Flag+n+1,false);
	while(b){
		Flag[b] = true;
		b = Path[b];
	}
	for(int i=1;i<=n;++i)if(Flag[i])printf("%d ",i);
	printf("\n");
    return 0;
}

T a r j a n Tarjan Tarjan算法

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

#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define hash_t unordered_map

typedef vector<int> vi;
typedef pair<int,int> pii;
typedef vi::const_iterator vcit;

//边双连通分量,可以处理重边,每个点唯一确定属于某个边双连通
//type of edge's weight
typedef int weight_t;

//just as its names
int const SIZE_OF_VERTICES = 120010;
int const SIZE_OF_EDGES = 200110;

struct edge_t{
	int from,to;
	//weight_t weight;
	int next;//Index of the array is used as pointers, ZERO means NULL
}Edge[SIZE_OF_EDGES];
int ECnt;
int Vertex[SIZE_OF_VERTICES];

//Don't forget calling it
//n is the amount of vertices
inline void initGraph(int n){
	ECnt = 2;
	fill(Vertex,Vertex+n+1,0);
}

//双向边
inline void mkEdge(int a,int b,weight_t w=weight_t()){
	Edge[ECnt].from = a;
	Edge[ECnt].to = b;
	//Edge[ECnt].weight = w;
	Edge[ECnt].next = Vertex[a];
	Vertex[a] = ECnt ++;

	Edge[ECnt].from = b;
	Edge[ECnt].to = a;
	//Edge[ECnt].weight = w;
	Edge[ECnt].next = Vertex[b];
	Vertex[b] = ECnt ++;
}

int Stack[SIZE_OF_VERTICES],StackTop;//辅助栈
int TimeStamp;
int Dfn[SIZE_OF_VERTICES], Low[SIZE_OF_VERTICES];
//bool IsBridge[SIZE_OF_EDGES];//边i是否为桥
bool IsVisited[SIZE_OF_EDGES];//边的标记数组,有重边时需用此数组进行判断
int Belong2BiCC[SIZE_OF_VERTICES];//点i属于第Bi个双连通分量,从1开始
int Represent[SIZE_OF_VERTICES];//Ri表示第i个边双的代表,也就是编号最小的那个点
int BiCCCnt;//双连通分量的数量

void dfs(int u,int pre){
    Dfn[u] = Low[u] = ++TimeStamp;

    //入栈
    Stack[StackTop++] = u;

    //对u的每一条边
    int v,son=0;
    for(int next=Vertex[u];next;next=Edge[next].next)if( !IsVisited[next] ){
        IsVisited[next] = IsVisited[next^1] = true;

        if ( 0 == Dfn[v=Edge[next].to] ){
            ++son;
            dfs(v,u);
            if ( Low[v] < Low[u] ) Low[u] = Low[v];

            /*//桥
            if ( Dfn[u] < Low[v] ){
                IsBridge[next] = IsBridge[next^1] = true;
            }
            //*/

        }else if ( Dfn[v] < Low[u] ){
            Low[u] = Dfn[v];
        }
    }

    if ( Low[u] == Dfn[u] ){//u和其上的点在同一个分量中
        Represent[Belong2BiCC[u] = ++BiCCCnt] = u;
        do{
            Belong2BiCC[v=Stack[--StackTop]] = BiCCCnt;
            if ( v < Represent[BiCCCnt] ) Represent[BiCCCnt] = v;
        }while( v != u );
    }
}

void Tarjan(int vn){
    fill(Dfn,Dfn+vn+1,0);
    fill(Belong2BiCC,Belong2BiCC+vn+1,0);
    fill(IsVisited,IsVisited+ECnt,false);
    //fill(IsBridge,IsBridge+ECnt,false);
    BiCCCnt = StackTop = 0;

    TimeStamp = 0;

    for(int i=1;i<=vn;++i)if ( 0 == Dfn[i] )dfs(i,i);
}

int Cnt[SIZE_OF_VERTICES] = {0};
int main(){
    // freopen("1.txt","r",stdin);
    // freopen("2.txt","w",stdout);
    int n;
	scanf("%d",&n);
	initGraph(n);
	for(int a,b,i=0;i<n;++i){
		scanf("%d%d",&a,&b);
		mkEdge(a, b);
	}
	if(1==n){
		puts("1");
		return 0;
	}
    Tarjan(n);
	int k = 0;
	/// 找到最大的边双
	for(int i=1;i<=n;++i){
        if(++Cnt[Belong2BiCC[i]]>1){
			k = Belong2BiCC[i];
			break;
		}
	}
	
	for(int i=1;i<=n;++i)if(Belong2BiCC[i]==k)printf("%d ",i);
	printf("\n");
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值