Vjudge程设练习组1题解

A - 谁都不准跟我抢吃的

题目描述:

艾丽叶来到了受灾非常严重的余姚。她的部队呢带着一大堆物资,现在需要运送给灾民们。艾丽叶作为一个ACMer酱,当然不能这么平庸的送物资了。不到十分钟,艾丽叶就想出了一个绝妙的计划:现在有Tom和Job两个灾民需要运送物资,艾丽叶随机给出一个数n(1<=n<=1500),Tom和Job需要在1~n(包括1和n)之内的所有素数中,由Job先开始,依次挑选一个素数,来拿走此编号的物资。直到谁挑走了最后一个素数为止。到最后谁拿不到素数,谁就能拿走最多的剩余物资,即win了。
Input
输入数据有多组。每组输入包含一个正整数n(1<=n<=1500)。【以0作为输入的结束】
Output
每组输入对应一个输出,对于每组输入,输出一行结果,即"Tom win"或者"Job win"。
Sample Input
1
2
0
Sample Output
Job win
Tom win

题解

判断素数,然后模拟一下

代码实现:

#include<stdio.h>
#include<math.h>
int judge(int m)//0素1合 
{
	if(m==1)return 1;
	if(m==2||m==3)return 0;
	for(int i=2;i<=sqrt(m);i++)
	{
		if(m%i==0)return 1;
	}
	return 0;
}
int main()
{
	int a[1505],flag=0,n;
	a[0]=0;
	for(int i=1;i<1505;i++)
	{
		if(judge(i)==0)a[i]=1-a[i-1];
		else a[i]=a[i-1];
	}
	while(1)
	{
		scanf("%d",&n);
		if(n==0)break;
		if(a[n]==0)printf("Job win\n");
		else printf("Tom win\n");
	} 
}

B - 字符统计

题目描述:

某人最近非常的奇怪,总是讲一些奇怪的字符串,然而这些字符串有些都是重复的。所以他很想知道,他说出的这个字符串在之前出现过了没有并且出现了几次,他很希望解决这个问题。
Input
题目包含多组数据。输入整数n(1 =< n <= 2000),代表说了n串字符串,接下来n行为字符串,字符串的长度(len <= 32),字符串仅包含小写的26个字母。
Output
每输入一串字符串输出一个答案,如果该字符串在之前没有出现过,那么就输出“OK”,如果出现过了,那么就输出该字符串,并且在字符串末尾输出出现的次数。
Sample Input
5
ab
ab
abc
abc
abc
Sample Output
OK
ab1
OK
abc1
abc2

题解

数据量很小,O(n2)逐个匹配即可

代码实现

#include<stdio.h>
#include<string.h>
int main()
{
	char ch[2005][40];
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		scanf("%s",ch[0]);
		printf("OK\n");
		for(int i=1;i<n;i++)
		{
			int sum=0;
			scanf("%s",ch[i]);
			for(int j=0;j<i;j++)
			{
				if(strcmp(ch[i],ch[j])==0)sum++;
			}
			if(sum==0)printf("OK\n");
			else printf("%s%d\n",ch[i],sum);
		}
	}
}

C- IP查询

题目描述

我们知道现实生活中每一个座城市对应一个IP段。现在为了简化问题,将IP端直接看作一个整型数,每座城市也有自己唯一的标识ID,也可以看做一个整数。那么问题来了,现在已知有多个闭区间代表多个IP段,每个区间对应一个城市的ID。现在Gealo要查询某个IP属于哪个城市,希望你们来帮他完成。

Input
第一行输入t,表示有t组数据(t <= 5)
接下来一行输入n,表示有n个区间(0 <= n<= 10^5)
接下来n行,每行输入三个整数x,y,id。代表区间[x,y]对应的城市ID。数据确保两个区间的交集为空,且ID唯一。(0 <=x<y<=10^8 , 0<= ID <= 10^8)
接下来一行输入一个整数m,代表m次查询(0 <= m <= 10^5)
接下来m行,每行输入一个整数x,代表所查询的IP(x <= 10^8)
Output
对于每次查询,输出一行,表示其对应的城市ID。
如果未找到就输出-1。
Sample Input
1
2
3 5 99
1 2 77
3
1
3
9
Sample Output
77
99
-1

题解

按左区间排序后二分查找

代码实现

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef struct Node  
{  
    int l;
    int r;
    int num;
}qujian;
qujian p[100005];
int sor(const Node a,const Node b)  
{
    return a.l<b.l;  
}
int search(int q,int len)  
{  
    int l=0,r=len-1;
    if(q<p[0].l)return -1;
    while(r>l)  
    {  
        int mnum=(l+r+1)/2;  
        if(q>=p[mnum].l)l=mnum;
        else r=mnum-1;
    }
    return l;  
}  
  
int main()  
{  
    int t,n,q,m,res;  
    scanf("%d",&t);  
    while(t--)  
    {
        scanf("%d",&n);  
        for(int i=0;i<n;i++)scanf("%d%d%d",&p[i].l,&p[i].r,&p[i].num);
        sort(p,p+n,sor);
        scanf("%d",&m);
        while(m--)
        {  
            scanf("%d",&q);  
            res=search(q,n);
            if(res!=-1)
            {
            	if(p[res].r>=q)printf("%d\n",p[res].num);  
            	else printf("-1\n");
			}
            else printf("-1\n");
        }  
    }
}

D - 迷路

题目描述

Leader Wang gets lost when he is walking in NB school.Now,there are many brands in the road.There will include the direction in brand(East, South, West and North).NB school is the size of M * N,and leader will follow the direction in brand,like map1 and map2.Can leader walk out of the map?
Input
Input until EOF.
First line contains two integets M(5<=M<=20) and N(5<=N<=20) indicates the size of school.
Next line contains two integets x(0<=x<M) and y(0<=y<N) indicates the starting position of leader.
Then M(from 0 to M-1) lines follows,each line contains N(from 0 to N-1) characters,every character(only is ‘N’ or ‘S’ or ‘W’ or ‘E’) indicates the direction in brand.
Output
If leader can walk out of the map,output “YES”,else output “NO”.
Sample Input
3 6
0 4
NEESWE
WWWESS
SNWWWW
4 5
0 0
SESWE
EESNW
NWEEN
EWSEN
Sample Output
YES
NO

题解

纯模拟 没啥好讲的 沿着字母走就行了 失败的条件是某一个格子被重复行走

代码实现

#include<stdio.h>
int main()
{
	int xx,yy,x,y;
	char mp[25][25];
	int np[25][25];
	while(scanf("%d%d",&xx,&yy)!=EOF)
	{
		for(int i=0;i<25;i++)for(int j=0;j<25;j++)np[i][j]=0;
		scanf("%d%d",&x,&y);
		np[x][y]=1;
		getchar();
		for(int i=0;i<xx;i++)
		{
			for(int j=0;j<yy;j++)scanf("%c",&mp[i][j]);
			getchar();
		}
		while(1)
		{
			if(mp[x][y]=='E')y++;
			else if(mp[x][y]=='W')y--;
			else if(mp[x][y]=='S')x++;
			else if(mp[x][y]=='N')x--;
			if(x<0||x>=xx||y<0||y>=yy)
			{
				printf("YES\n");
				break;
			}
			if(np[x][y])
			{
				printf("NO\n");
				break;
			}
			np[x][y]=1;
		}
	}
}

E - To be or not to be

题目描述

To chat or not to chat, it is a question. Zero is so angry because when he plays LOL, there is nobody plays with him. So, zero wants to punish them.
Now, the rule is that there are almost N men, everybody can play with others. But, if one of them who plays with M people, these M people can not play with each other
Now we agreed that one plays with another to be a playing relationship.
For example, if man A plays with man B, man C, man D, then man B can not play with man C and man D, of course the same as man C and man D. And there are three playing relationships.
There are N people, can you get the maximum number of playing relationships.

Input
Input until EOF.
Each line contains one integer N(1 < N <= 10^9) means the number of people.
Output
One line one output, print the maximum number of playting relationships.
Sample Input
2
3
4
Sample Output
1
2
4

题解

可以画个图连一下 n偶数的情况下答案是n^2/4 n为奇数的情况下答案是(n-1)/2)乘((n-1)/2)+((n-1)/2)。具体最优解 举个例子 比如六个点排成正六边形 在将六边形的边都连好后 将对角的线也连起来 这样每个点都连了6/2=3条边 所以答案是(6/2)乘6/2。当六个点变成八个点后 八个点排成正八边形 同样连好边后 每个点可以再额外连2条线 这样每个点都练了8/2=4条边 答案是(8/2)乘8/2 以此类推。奇数的话 举一个例子 n=7的时候 我们把6个点的情况连好(上面解释过6个点的连法了) 然后额外的那个点隔一个连一个 就是ans(6)+(7-1)/2=9+3=12条。所以奇数的通项就是(n-1)/2)乘((n-1)/2)+((n-1)/2) 第一个单项式其实是n-1的条数答案 后面再加一个 多出来的点的线数即可。

代码实现

#include<stdio.h>
int main()
{
	long long n;
	while(scanf("%lld",&n)!=EOF)n%2==0?printf("%lld\n",(n/2)*(n/2)):printf("%lld\n",((n-1)/2)*((n-1)/2)+((n-1)/2));
}

F - 树的宽度

题目描述

It’s an easy problem. I will give you a binary tree. You just need to tell me the width of the binary tree.
The width of a binary tree means the maximum number of nodes in a same level. 树的宽度定义为它某一层节点总数的最大值

For example, the width of binary tree above is 3.

Input
The first line is an integer T, means the number of cases.
Then follow T cases.
For each case, the first line is an integer N, means the number of nodes. (1 <= N <= 10)
Then follow N lines. Each line contains 3 integers P A B; indicate the number of this node and its two children node. If the node doesn’t have left child or right child, then replace it by -1. 接下来的N行,每行包含三个整数P A B,表示第P个节点的两个子节点分别是A和B,而如果某个子节点为空,则用-1表示
You can assume the root is 1. 编号1的节点是整棵树的根
Output
For each case, output the width.
Sample Input
1
6
4 -1 -1
2 4 5
5 -1 -1
1 2 3
6 -1 -1
3 -1 6
Sample Output
3

题解

比较基础的数据结构题,先进行二叉树的建立,然后再递归,每层递归都记录一下当前层的点的个数

代码实现

#include<stdio.h>
struct node
{
	int depth;
	int child;
	struct node *left;
	struct node *right;
}no[12];
int dep[15];
void search(node *p,int depth)
{
	dep[depth]++;
	if(p->left!=NULL)search(p->left,depth+1);
	if(p->right!=NULL)search(p->right,depth+1);
}
int main()
{
	int t,n,p,l,r,max=0;
	scanf("%d",&t);
	while(t--)
	{
		max=0;
		for(int i=0;i<12;i++)
		{
			no[i].depth=0;
			no[i].child=0;
			no[i].left=NULL;
			no[i].right=NULL;
			dep[i]=0;
		}
		scanf("%d",&n);
		for(int k=0;k<n;k++)
		{
			scanf("%d%d%d",&p,&l,&r);
			if(l!=-1)
			{
				no[p].left=&no[l];
				no[l].child=1;
			}
			if(r!=-1)
			{
				no[p].right=&no[r];
				no[r].child=1;
			}
		}
		search(&no[1],1);
		for(int i=1;i<11;i++)if(dep[i]>max)max=dep[i];
		printf("%d\n",max);
	}
}

G - 数组查询

题目描述

给你一个N元素的数组,下标从1到N,现在要查询从I到J的最小值
Input
Input starts with an integer T (≤ 5), denoting the number of test cases.

The first line of a case is a blank line. The next line contains two integers N (1 ≤ N ≤ 105), q (1 ≤ q ≤ 50000). The next line contains N space separated integers forming the array. There integers range in [0, 105].

The next q lines will contain a query which is in the form I J (1 ≤ I ≤ J ≤ N).

Output
For each test case, print the case number in a single line. Then for each query you have to print a line containing the minimum value between index I and J.

Sample Input
2

5 3
78 1 22 12 3
1 2
3 5
4 4

1 1
10
1 1
Sample Output
Case 1:
1
3
12
Case 2:
10
Note
Dataset is huge. Use faster I/O methods.

题解

G就是典型的RMQ题目,可以建立ST表实现O(1)查询,当然这里使用的是朴素的线段树

代码实现

#include<stdio.h>
#define MAX 999999999
int xiao(int a,int b)
{
	if(a>b)return b;
	else return a;
}
int line[900012];
void tree(int k,int l,int r)
{
	int mid=(l+r)/2;
	if(l!=r)
	{
		tree(k<<1,l,mid);
		tree(k<<1|1,mid+1,r);
		line[k]=xiao(line[k<<1],line[k<<1|1]);
	}
	else scanf("%d",&line[k]);
}
int check(int k,int ll,int rr,int l,int r)
{
	if(l<=ll&&rr<=r)return line[k];
	int min=MAX;
	int mid=(ll+rr)/2;
	if(l<=mid)min=xiao(min,check(k<<1,ll,mid,l,r));
	if(r>mid)min=xiao(min,check(k<<1|1,mid+1,rr,l,r));
	return min;
}
int main()
{
	int t,n,m,l,r;
	scanf("%d",&t);
	for(int p=0;p<t;p++)
	{
		printf("Case %d:\n",p+1);
		scanf("%d%d",&n,&m);
		tree(1,1,n);
		while (m--)
		{
			scanf("%d%d",&l,&r);
			printf("%d\n",check(1,1,n,l,r));
		}
	}
}

H - 正整数划分

题目描述

整数n可以划分成一些正整数之和,问有多少种不同的划分方法。
比如4可以划分成{1,1,1,1},{1,1,2},{1,3},{2,2},{4}共5种方法,注意{1,3}和{3,1}是同一种方法。
Input
有几个测试样例。 每个测试样例输入一个数n(1<=n<=120)。请处理到文件末。
Output
对于每一个测试样例,输出一个答案表示不同的划分数占一行。
Sample Input
4
10
20
Sample Output
5
42
627

题解

动态规划(严格意义上应该也不算 算是递推) 用动归和递归实现应该都可以

代码实现

#include<stdio.h>
int a[122][122];
int main()
{
	int n;
	for(int i=0;i<122;i++)
	{
		a[i][0]=1;
		a[i][1]=1;
		a[0][i]=1;
		a[1][i]=1;
	}
	for(int i=2;i<122;i++)
	{
		for(int j=2;j<122;j++)
		{
			if(i>=j)a[i][j]=a[i][j-1]+a[i-j][j];
			else a[i][j]=a[i][i];
		}
	}
	while(scanf("%d",&n)!=EOF)printf("%d\n",a[n][n]);
}

I - 连续整数和

题目描述

Given an integer N, you have to find the number of ways you can express N as sum of consecutive integers. You have to use at least two integers.

For example, N = 15 has three solutions, (1+2+3+4+5), (4+5+6), (7+8).

Input
Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case starts with a line containing an integer N (1 ≤ N ≤ 1014).

Output
For each case, print the case number and the number of ways to express N as sum of consecutive integers.

Sample Input
5
10
15
12
36
828495
Sample Output
Case 1: 1
Case 2: 3
Case 3: 1
Case 4: 2
Case 5: 47

题解

首先对于每一个a(首项)通过等差数列求和公式来确定合适的k(长度),最后能推出来 合适的k需要满足2乘n/k-k=2乘a-1 这时候就变成找n的因子了 但是因为2乘a-1是奇数,所以是找n的奇数因子,可以事先打表把质数关系先找出来 方便后面用(不然mle+tle整到疯)

代码实现

#include <stdio.h>
const int N=10000000;
bool a[10000000];
int prime[1000000];
int main()
{
	long long sum,total,med=0;
	int t,num=0;
	for(long long i=2;i<N-1;i++)a[i]=0;
	for(long long i=2;i<N-1;i++)if(a[i]==0)for(long long j=i*2;j<N-1;j+=i)a[j]=1;
	for(long long i=2;i<N-1;i++)
	{
		if(a[i]==0)
		{
			prime[num]=i;
			num++;
		}
	}
	scanf("%d",&t);
	for(int k=1;k<=t;k++)
	{
		long long total=0;
		scanf("%lld",&sum);
		total++;
		for(int i=0;i<num;i++)
		{
			//if(prime[i]==0)continue;
			if(prime[i]*prime[i]>sum)break;
			med=0;
			if(sum%prime[i])continue;
			while(sum%prime[i]==0)
			{
				sum/=prime[i];
				med++;
			}
			if(prime[i]%2==1)total*=med+1;
		}
		if(sum%2&&sum>1)total*=2;
		total--;
		printf("Case %d: %lld\n",k,total);
	}
}

J - 博麗靈夢的飛行

题目描述

博麗靈夢(はくれい·れいむ)有个非常厉害的能力,能瞬间飞行到另一个地方,即瞬移。

不过,在草地上飞行的时候,所带来的强大风能让草指向她的飞行方向。一开始,所有的草都是指向天上的。

现在,靈夢在草地上左右飞行,在靈夢飞行后,你需要统计出有多少地方的草是向左的、向右的、朝天的

Input
有多组测试数据

每组第一行输入m和n(0 < m <= 10000, 0 < n <= 100000)

m表示接下来有多少次飞行和查询,n表示这个草地的最大长度
接着是m行,每行格式为:

F a b 表示从a点开始,飞到b点
Q a b 查询从a到b

其中 1 <= a,b <= n,而查询时,a<=b

Output
对于每个Q查询,依次输出向左的草的数量,朝天的草的数量,向右的草的数量

Sample Input
3 10
F 1 3
F 10 9
Q 1 10
1 10
Q 1 10
Sample Output
2 5 3
0 10 0
Hint
For the first sample, the grass will be “rrrtttttll” when querying

题解

区间操作+查询题,板子很多,不知道区间覆盖的板子能不能用,因为一开始套了区间加法的板子,所以最后强行把l和r的映射到一个值里(r的值1000000+l的值1,t=length-r-l所以不需要标记)其他的传统的pushdown和pushup都一样

代码实现

#include<stdio.h>
const long long leftlength=10000000;
const long long rightlength=1;
typedef struct node
{
	long long l;
	long long r;
	long long sum;
	long long mark;
}node;
node no[400007];
long long save;
void build(int k,int l,int r)
{
	no[k].l=l;
	no[k].r=r;
	no[k].sum=0;
	no[k].mark=0;
	if(l==r)return;
	else
	{
		build(k*2,l,(l+r)/2);
		build(k*2+1,(l+r)/2+1,r);
	}
}
void change(int k,int l,int r,long long v)
{
	int len,lenn;
	if(l<=no[k].l&&no[k].r<=r)
	{
		no[k].sum=v;
		no[k].mark=v*no[k].r-v*(no[k].l-1);
		return;
	}
	len=(no[k].r-no[k].l+1);
	lenn=len/2;
	if(no[k].sum!=0)
	{
		lenn=len/2;
		no[k*2].sum=no[k].sum;
		no[k*2].mark=no[k].sum*(len-(lenn));
		no[k*2+1].sum=no[k].sum;
		no[k*2+1].mark=no[k].sum*lenn;
		no[k].sum=0;
	}
	if(r<=(no[k].l+no[k].r)/2)change(k*2,l,r,v);
	else if(l>(no[k].l+no[k].r)/2)change(k*2+1,l,r,v);
	else
	{
		change(k*2,l,(no[k].l+no[k].r)/2,v);
		change(k*2+1,(no[k].l+no[k].r)/2+1,r,v);
	}
	no[k].mark=no[k*2].mark+no[k*2+1].mark;
}
void check(int k,int l,int r)
{
	int len,lenn;
	if(l<=no[k].l&&r>=no[k].r)
	{
		save+=no[k].mark;
		return;
	}
	len=(no[k].r-no[k].l+1);
	lenn=len/2;
	if(no[k].sum!=0)
	{
		lenn=len/2;
		no[k*2].sum=no[k].sum;
		no[k*2].mark=no[k].sum*(len-(lenn));
		no[k*2+1].sum=no[k].sum;
		no[k*2+1].mark=no[k].sum*lenn;
		no[k].sum=0;
	}
	if(r<=(no[k].l+no[k].r)/2)check(k*2,l,r);
	else if(l>(no[k].l+no[k].r)/2)check(k*2+1,l,r);
	else
	{
		check(k*2,l,(no[k].l+no[k].r)/2);
		check(k*2+1,(no[k].l+no[k].r)/2+1,r);
	}
}
int main()
{
	int m,n,ll,rr,length;
	char ch;
	long long ansl,anst,ansr;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		build(1,1,n);
		while(m--)
		{
			getchar();
			save=0;
			scanf("%c",&ch);
			if(ch=='F')
			{
				scanf("%d%d",&ll,&rr);
				if(ll>rr)
				{
					change(1,rr,ll,leftlength);
					length=ll-rr+1;
				}
				else
				{
					change(1,ll,rr,rightlength);
					length=rr-ll+1;
				}
			}
			else
			{
				scanf("%d%d",&ll,&rr);
				length=rr-ll+1;
				check(1,ll,rr);
				ansl=save/leftlength;
				ansr=save%leftlength;
				anst=length-ansl-ansr;
				printf("%lld %lld %lld\n",ansl,anst,ansr);
			}
		}
	}
}

K - 第k个排列

题目描述

Given a string of characters, we can permute the individual characters to make new strings. At first we order the string into alphabetical order. Then we start permuting it.

For example the string ‘abba’ gives rise to the following 6 distinct permutations in alphabetical order.

aabb 1

abab 2

abba 3

baab 4

baba 5

bbaa 6

Given a string, you have to find the nth permutation for that string. For the above case ‘aabb’ is the 1st and ‘baab’ is the 4th permutation.

Input
Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case contains a non empty string of lowercase letters with length no more than 20 and an integer n (0 < n < 231).

Output
For each case, output the case number and the nth permutation. If the nth permutation doesn’t exist print ‘Impossible’.

Sample Input
3
aabb 1
aabb 6
aabb 7
Sample Output
Case 1: aabb
Case 2: bbaa
Case 3: Impossible

题解

首先排除std库的下一个序列函数 铁tle 这个其实就是逆康托展开 只不过难度再大一点 需要一点排列组合的知识 先举无重复字符的例子 比如abcd 当a作为第一个时,一共有(4-1)!种情况,然后和答案进行对比,如果答案<3!则a是第一个字符,若不是则换下一个字符,因为就20个字符所以暴力找就行。对于有重复字符的,比如abbbccc,当a作为第一个字符后,一共的情况数是6!/(3!*3!) 其实就是排除相同字符内部排序的影响 再重复上面的操作就行

代码实现

#include<stdio.h>
#include<string.h>
const int word=26;
long long jiecheng(int a)
{
	if(a==0)return 1;
	long long sum=1;
	for(int i=2;i<=a;i++)sum*=i;
	return sum;
}
int main()
{
	int t,n,len,count[word],stalen;
	long long temp,max;
	char ch[22];
	scanf("%d",&t);
	for(int l=1;l<=t;l++)
	{
		for(int i=0;i<word;i++)count[i]=0;
		scanf("%s%d",ch,&n);
		len=strlen(ch);
		max=jiecheng(len);
		for(int i=0;i<len;i++)count[ch[i]-'a']++;
		for(int i=0;i<word;i++)if(count[i])max/=jiecheng(count[i]);
		if(n>max)printf("Case %d: Impossible\n",l);
		else
		{
			printf("Case %d: ",l);
			stalen=len;
			for(int i=0;i<stalen;i++)
			{
				for(int j=0;j<word;j++)
				{
					if(!count[j])continue;
					count[j]--;
					temp=jiecheng(len-1-i);
					for(int k=0;k<word;k++)if(count[k])temp/=jiecheng(count[k]);
					if(temp>=n)
					{
						printf("%c",'a'+j);
						break;
					}
					else
					{
						count[j]++;
						n-=temp;
					}
				}
			}
			printf("\n");
			max=0;
		}
	}
}
发布了8 篇原创文章 · 获赞 1 · 访问量 327

猜你喜欢

转载自blog.csdn.net/weixin_42921101/article/details/104276230