首页 > 代码库 > 南京理工大学第八届程序设计大赛(校外镜像)题解报告

南京理工大学第八届程序设计大赛(校外镜像)题解报告

整体来说,这次的题目还是不错的,只是有几题居然是原题,着实有点让人心醉...

链接→南京理工大学第八届程序设计大赛(校外镜像)

A.偷吃糖果

Time Limit: 1000Ms

Memory Limit: 65536KB

Description

小鱼喜欢吃糖果。

他有两盒糖果,两盒糖果分别仅由小写字母组成的字符串s和字符串t构成。当中‘a‘到‘z‘表示详细的某种糖果类别。他原本打算送给他喜欢的女生,可是要送给女孩子的话两盒糖果不能有区别(即字符串s和t全然同样)。所以,他决定偷吃几块,他吃糖果的策略是每次选出一盒糖果中两个连续的同种类别的糖果,然后吃掉当中一块。该策略能够使用多次

比如一盒糖果是‘rrrjj‘,他能够把这盒糖果变成‘rrjj‘或者‘rrrj‘。如今你要告诉小鱼。经过他多次偷吃糖果之后。两盒糖果是否能送给他喜欢的女孩子。假设能够输出‘Yes‘,假设不行输出‘No‘。

Input

第一行一个T,表示T组測试数据。每组測试数据格式例如以下。第一行表示字符串s,第二行表示字符串t。

1 ≤ T ≤ 100Each character of s, t will be between ‘a‘ and ‘z‘.1 ≤ length of string s ≤ 10001 ≤ length of string t ≤ 1000

Output

对于每组測试数据。输出Yes,或者No。

Sample Input

2
rrrjj
rrrj
rj
jr

Sample Output

Yes
No

Hint

题目中的第一个例子:
第一盒糖果:rrrjj -> rrjj -> rjj -> rj
第二盒糖果:rrrj -> rrj -> rj

解题思路:此题思路还是简单的,由于题目明白吃糖果的策略为每次选出一盒糖果中两个连续的同种类别的糖果,然后吃掉当中一块,所以对于每一种糖果,仅仅要一開始有,那么终于必然至少会留下一块,那么为了便于处理,我们能够将两个字符串简化,同种类别糖果仅仅留下一块,以便于比較

比如第一组例子,rrrjj与rrrj,简化后的效果为rj与rj,非常明显符合

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<deque>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 1000 + 10;
const int M = 40;
const int inf = 100000000;
const int mod = 2009;
char a[N],b[N];
int main()
{
    int t,i,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s%s",a,b);
        k=0;
        a[k++]=a[0];
        for(i=1;a[i]!='\0';i++)
            if(a[i]==a[i-1])
                continue;
            else
                a[k++]=a[i];
        a[k++]='\0';
        //puts(a);
        k=0;
        b[k++]=b[0];
        for(i=1;b[i]!='\0';i++)
            if(b[i]==b[i-1])
                continue;
            else
                b[k++]=b[i];
        b[k++]='\0';
        //puts(b);
        if(strcmp(a,b))
            puts("No");
        else
            puts("Yes");
    }
    return 0;
}


C.count_prime

Time Limit: 1000ms

Memory Limit: 65536KB

Description

给定你一个数n,请你统计出在[a,b]这个区间中和n互质的数的个数。

两个数互质当且仅当他们除了1之外没有其它的公共因子或者他们最大的公共因子是1。1和不论什么数是互素的。

Input

第一行输入一个整数T(1 <= T <= 100)。表示T组測试数据。接下来T行。每行3个整数a,b。n(1 <= a <=b <=10^15, 1<= n <= 10^9),用空格隔开。

Output

输出一个整数表示和n互质的数的个数。

Sample Input

2
1 10 2
3 10 5

Sample Output

5
6

Hint


解题思路:求[a,b]区间内与n互质的数的个数,我们能够转化为[1,b]内与n互质的数的个数减去[1,a-1]内与n互质的数的个数

而要求[1,b]内与n互质的数的个数,我们能够非常自然地想到容斥原理

求解区间[a,b]中与k互质的个数
首先对k进行质数分解,然后与这个因子GCD!=1则共同拥有n/k
i

有计算反复的部分,因此利用 容斥原理: k1+k2+k3-k1*k2-.....求出与k不互质的个数。用总的减去就可以

然后blabla,就是单纯的容斥原理模板题,话说此题就是一道原题,hdu4135

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<deque>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
#define ll long long
using namespace std;
const int N = 20 + 10;
const int M = 10000 + 10;
const int inf = 100000000;
const int mod = 2009;
int k,prime[N];
ll factor[M];
void get_prime(ll n)
{
    k=0;
    for(ll i=2;i*i<=n;i++)
        if(n%i==0)
        {
            prime[k++]=i;
            while(n%i==0)
                n/=i;
        }
    if(n>1)
        prime[k++]=n;
}
ll Exclusion(ll n)
{
    int i,j,p=0,q;
    ll sum=0;
    factor[p++]=-1;
    for(i=0;i<k;i++)
    {
        q=p;
        for(j=0;j<q;j++)
            factor[p++]=factor[j]*prime[i]*(-1);
    }
    for(i=1;i<p;i++)
        sum+=n/factor[i];
    return sum;
}
int main()
{
    int t;
    ll a,b,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld%lld",&a,&b,&n);
        get_prime(n);
        printf("%lld\n",b-Exclusion(b)-(a-1-Exclusion(a-1)));
    }
    return 0;
}


D.triple

Time Limit: 3000MS

Memory Limit: 65536KB

Description

给出一个整数n。表示1,2。...,n。从这n个数中随意选择3个不同的数字x。y,z。问x,y,z的最大公约数等于m的方案有多少种?(注意:(1,2,3),(1,3,2),(2,1,3)。(2,3,1),(3,1,2),(3,2,1)属于同一种方案)

Input

第一行输入一个整数T(1 <= T <= 100)。表示有T组数据,接下来T行。每行2个整数n, m(1 <= m <= n <= 10^5)

Output

输出一个整数表示答案

Sample Input

1
5 1

Sample Output

10

Hint


解题思路:据说是莫比乌斯反演,只是本人并没有搞出来,看看日后会不会更它,主要看我懒不懒

此处临时放上一种AC的代码


#include<stdio.h>
#include<math.h>
#define LL long long
#define MAXN 100010
LL C[MAXN]={0};
void Init(){
	C[1]=C[2]=0;
	LL i,j;
	for(i=3;i<MAXN;i++)
		C[i]=i*(i-1)*(i-2)/6;
}
LL digui(int N){
	if(N<3)
		return 0;
	if(N==3)
		return 1;
	int i;
	LL sum;
	for(i=2,sum=0;i<N;i++){
		if(N/i>=3){
			sum+=digui(N/i);
		}
	}
	return C[N]-sum;
}
int main(){
	int T;
	int N,M;
	scanf("%d",&T);
	Init();
	while(T--){
		scanf("%d%d",&N,&M);
		if(N/M<3)
			printf("0\n");
		else{
			printf("%lld\n",digui(N/M));
		}
	}
	return 0;
}



F.sequence

Time Limit: 1000MS

Memory Limit: 65536KB

Description

将一个给定的数列,拆分成K个不降序列,每一个数出现且仅仅出现一次,且在各序列中各个数相对于原数列的相对顺序不变。如7 6 9 8 10能够拆成 7 9 10和6 8。

求最小的K值。

Input

第一行输入一个整数T(1 <= T <= 100)。表示接下来T组測试数据,每组两行,第一行为n,代表数列长度(1<=n<=10000)接下来一行有n个数,空格分隔(每一个数<=50000)。

Output

对每组数据输出一个最小的K值。

Sample Input

2
5
7 6 9 8 10
5
5 4 3 2 1

Sample Output

2
5

Hint


解题思路:不得不说,这是第二道原题,有印象的同学必然会记得"最少拦截系统",只是hdu的数据就有点水了,不是正解

我的做法是用STL set来模拟,由于set会自己主动帮我们排序,而每次进来的数,要找比当前进来的数小的最大数进行更新,假设不存在则插入一个新的,终于set的大小size()就是题目要求的结果

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<deque>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
#define ll long long
using namespace std;
const int N = 20 + 10;
const int M = 10000 + 10;
const int inf = 100000000;
const int mod = 2009;
set<int> s;
set<int>::iterator it1,it2;
int main()
{
    int t,x,n,i;
    scanf("%d",&t);
    while(t--)
    {
        s.clear();
        scanf("%d",&n);
        scanf("%d",&x);
        s.insert(x);
        for(i=1;i<n;i++)
        {
            scanf("%d",&x);
            it2=s.upper_bound(x);
            it1=it2;
            it1--;
            if(it2==s.begin())
                s.insert(x);
            else
            {
                s.erase(it1);
                s.insert(x);
            }
        }
        printf("%d\n",s.size());
    }
    return 0;
}


G.琪露诺的算术教室

Time Limit: 1000ms

Memory Limit: 65536KB

Description

给出一个非负整数A,将这个数字的最低位移动到最高位(原来的最高位变为次高位。次低位变成最低位),得到非负整数B。发现B恰好是A的k倍。

现给出A的最低位的值n,和倍数k。求最小的非负整数B。

Input

第一行输入一个正整数T(1 <= T <= 1000),表示有T组測试数据。

对于每组測试数据:输入两个整数n,k(0<=n<=9 , 0<=k<=9)。

Output

对于每组測试数据,输出一个非负整数B,若无解,请输出-1。

Sample Input

1
2 2

Sample Output

210526315789473684

Hint


解题思路:首先,我们已经知道了B的最高位数字为n,那么我们就能够来模拟一下除法的过程

就拿例子来举例子

技术分享

我们每一轮除法得到的商会作为下一轮的被除数,当然,不能忘了考虑上一轮由于除不尽留下的余数,就这样一直计算到被除数s[i]能被除数k整除且商为n的时候结束

除了n=0,k=0时,B=0

其它k=0的时候,B=-1(无解)

由上述方法算出的结果还让我错了一次

比如n=1,k=2时,B=105263157894736842,那么A=052631578947368421,非常显然,这样是不正确的,移动前的A不可能含有前导0,所以我们还要推断当B的位数>=2时,从高到低来看,第二位不能为0,否则也是无解的情况

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<deque>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
#define ll long long
using namespace std;
const int N = 10000 + 10;
const int M = 10000 + 10;
const int inf = 100000000;
const int mod = 2009;
int ans[N],s[N];
int main()
{
    int t,n,k,p,i,c;
    scanf("%d",&t);
    while(t--)
    {
        i=p=c=0;
        scanf("%d%d",&n,&k);
        if(!n&&!k)
        {
            puts("0");
            continue;
        }
        if(!k)
        {
            puts("-1");
            continue;
        }
        s[i]=n;
        while(!((s[i]+c)%k==0&&(s[i]+c)/k==n))
        {
            ans[p]=(s[i]+c)/k;
            c=((s[i]+c)%k)*10;
            i++;
            s[i]=ans[p];
            p++;
        }
        if(s[1]==0&&p>=2)
        {
            puts("-1");
            continue;
        }
        for(i=0;i<=p;i++)
            printf("%d",s[i]);
        puts("");
    }
    return 0;
}


H.谁才是最强战舰!

Time Limit: 1000MS

Memory Limit: 65536KB

Description

依阿华来到镇守府的第一件事情,就是找大和solo。然而这并非什么好消息,说不定,镇守府。甚至佐伯湾就这么消失了。。。

于是,提督君想了一个简单的游戏,来分出她们的胜负。

游戏规则例如以下:这里有N堆石子,每堆石子有a[i](1<=i<=N)个。每人轮流从当中的某一堆石子中拿出随意个石子(仅仅能在当中一堆拿。不能不拿),大和先手。谁拿出了最后一个石子,谁输。若大和必胜,输出“Yamato_Saikou!”,若依阿华必胜,输出“Meidikeji_Shijiediyi!”。若两边都无法必胜。输出“Sayonara_Konosekai!”.

Input

第一行输入一个正整数T(1 <= T <= 1000),表示有T组測试数据。

对于每组測试数据:第一行一个正整数,N(N<=1000),表示有N堆石子。第二行N个整数a[i](1<=a[i]<=1000),表示每堆石子的数量。

Output

若大和必胜,输出“Yamato_Saikou!”,若依阿华必胜。输出“Meidikeji_Shijiediyi!”。若两边都无法必胜。输出“Sayonara_Konosekai!”.

Sample Input

3
1
5
2
1 2
3
1 1 1

Sample Output

Yamato_Saikou!
Yamato_Saikou!
Meidikeji_Shijiediyi!

Hint


解题思路:非常显然,这是一道博弈题,并且是尼姆博弈的变型,谁拿完谁输,本人还是用了模板,有兴趣学习一下尼姆博弈的能够点此链接->尼姆博弈

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<deque>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100000 + 10;
const int M = 40;
const int inf = 100000000;
const int mod = 2009;
long long h[N],w[N];
int main()
{
    int t,x,ans,n,i,c;
    int num1,num2;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        ans=num1=num2=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            if(x==1)
            num1++;         //孤单堆
            else
            num2++;        //充裕堆
            ans^=x;
        }
        if((ans&&num2!=0)||(!ans&&num2==0))  //S1,S2,T0必胜
            puts("Yamato_Saikou!");
        else                                  //S0,T2必败
            puts("Meidikeji_Shijiediyi!");
    }
    return 0;
}


J.water1

Time Limit: 1000MS

Memory Limit: 65536KB

Description

听说全球气候变暖。冰川融化,海水淹大地。着实好奇要融化多少冰川会淹没我的宿舍,哦不,淹没南京,反正NJUST应该总会是第一批被淹的。现将问题简化成一个二维坐标系的模型。有N个矩形块区域,每一个区域有海拔(H)和宽度(W),区域依照顺序给出,比方有3个区域,第一个区域宽度为1。海拔为2,第二个区域宽度为5。海拔为6。第三个区域宽度为3,海拔为4。从图像上看就是像这样:(Y轴是海拔)
 +++++
 +++++
 ++++++++
 ++++++++
2 +++++++++
1 +++++++++
  123456789
如果最左边和最右边都是无限高的墙。

为了简化问题。如果水流下来的速度是每秒一个单位的水。而且总是往区域一降水(某沿海地区)。

如今请问要淹没全部的区域至少要多少时间(秒)?淹没的定义是,全部的区域表面至少覆盖一层水。如果没有区域则至少要放一滴水。上图样例中,淹没完例如以下:

8
7 wwwwwwwww
6 w+++++www
5 w+++++www
4 w++++++++
3 w++++++++
2 +++++++++
1 +++++++++
  123456789
所以须要19秒。

Input

多CASE,測试数据以EOF结尾。对于每一个CASE:第一行一个整数N(0 <= N <= 10^5)。接下去N行每行相应两个整数H(1 <= H <= 10^5),W(1 <= W <= 10^5)分别相应第N个区域的海拔和宽度。

Output

一个整数,表示所须要的时间。

Sample Input

3
2 1 
6 5
4 3

Sample Output

19

Hint


解题思路:题目告诉我们‘+‘的高度和宽度,要我们填‘w‘,最顶层须要一层的‘w‘,问须要多少个‘w

题目明白当N=0时,ans=1;

所以我们仅仅须要找到最大海拔值Max+1

那么终于所须要的‘w‘个数即为

ans+=(Max-h[i])*w[i];

此题一開始着实被__int64坑了一把,该站点仅支持long long,并且输入输出的时候还得用%lld,不然居然是Presentation Error,这就不能忍了,凭什么不是Wrong Answer!!!好吧,此题会超int

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<deque>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100000 + 10;
const int M = 40;
const int inf = 100000000;
const int mod = 2009;
long long h[N],w[N];
int main()
{
    int n,i;
    long long ans,Max;
    while(~scanf("%d",&n))
    {
        Max=ans=0;
        for(i=0;i<n;i++)
        {
            scanf("%lld%lld",&h[i],&w[i]);
            Max=max(Max,h[i]);
        }
        Max++;
        for(i=0;i<n;i++)
            ans+=(Max-h[i])*w[i];
        long long s=1;
        printf("%lld\n",max(ans,s));
    }
    return 0;
}
菜鸟成长记

南京理工大学第八届程序设计大赛(校外镜像)题解报告