HHU ACM综合训练1 Problem A ~ E


问题 A: Kingdom of Black and White

题目描述

In the Kingdom of Black and White (KBW), there are two kinds of mice: black mouse and white mouse.

Now N mice are standing in a line, some of them are black, the others are white. The total strength of those mice are calculated by dividing the line into minimum parts, each part should still be continuous, and can only contain one kind of mouse. Then the strength is the sum of the squared length for each part.

However, an old, evil witch comes, and tells the mice that she will change the color of at most one mouse and thus the strength of those mice might change.

The mice wonder the maximum possible strength after the witch finishes her job.

输入

First line contains an integer T, which indicates the number of test cases.

Every test case only contains a string with length N, including only 0 (representing a black mouse) and 1 (representing a white mouse).

⋅ 1≤T≤50.

⋅ for 60% data, 1≤N≤1000.

⋅ for 100% data, 1≤N≤10 5.

⋅ the string only contains 0 and 1.
 

输出

For every test case, you should output "Case #x: y",where x indicates the case number and counts from 1 and y is the answer.

样例输入

2
000011
0101

样例输出

Case #1: 26
Case #2: 10

题意:给定一个长度为N只含0 1的字符串。字符串按照相同的数字被分为不同的部分,字符串的和为每个部分的平方的和。现在修改至多1个数字,使字符串和最大。

对于和最大的情况,应该是某个部分相同的数字尽可能的多。(因为sum^2>(sum-1)^2+1,sum为前面相同数字部分的总和)

直接对某个位置进行0 1的替换较为麻烦,因此我们想到将相同的数字分为一个块,每个块的结果就是这个块相同数字的数量:

如000011就分块为a[1]=4 a[2]=1;

这样的好处是,当进行某个数字的替换操作时,实际上就是前一个块、当前块、后一个块的变化;并且如果假设当前块为第i个块,那么i-1之前的块和i+1之后的块的和是不变的;

接下来只要对a[i]这个块是否为1判断就可以了:

如果a[i]=1,它的改变会让i-1块、i块、i+1块合并,取合并后的值和不改变时的值的最大值;

如果a[i]!=1,它的改变会有两种情况,要么让第i块合并到前面,要么合并到后面,要么不改变,取最大值即可。

因为a[i]的时候会访问到未输入的a[i-1] a[i+1] 所以之前记得把它们初始化为0;

循环条件访问到a[i]结束,即j-1;

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=100010;
char s[N];
ll a[N];
ll sqr(ll x){
	return x*x;
}
int main(){
	int t,cas=1;
	scanf("%d",&t);
	while(t--){
		scanf("%s",s);
		int l=strlen(s);
		ll cnt=1,j=1;
		ll sum=0,ans=0;
		for(int i=1;i<l;i++){
			if(s[i]==s[i-1]) cnt++;
			else{
				a[j++]=cnt;
				sum+=sqr(cnt);
				cnt=1;
			}
		}
		if(j==1){	
			sum=sqr(cnt);
			printf("Case #%d: %lld\n",cas++,sum);	
			continue;
		}
		a[j++]=cnt;sum+=sqr(cnt);a[j++]=0;a[0]=0;
	
	
		
		for(int i=1;i<j-2;i++){
			if(a[i]==1){
				ans=max(ans,sum-sqr(a[i-1])-sqr(a[i])-sqr(a[i+1])+sqr(a[i-1]+a[i]+a[i+1]));
			}
			else{
				ans=max(ans,max(sum-sqr(a[i])-sqr(a[i+1])+sqr(a[i]-1)+sqr(a[i+1]+1),sum-sqr(a[i])-sqr(a[i+1])+sqr(a[i]+1)+sqr(a[i+1]-1)));
			
			}
		}

		printf("Case #%d: %lld\n",cas++,ans);	
	}
}




问题 B: Friendship of Mouse


题目描述

Today in KBW, N mice from different cities are standing in a line. Each city is represented by a lowercase letter. The distance between adjacent mice (e.g. the 1 st and the 2 nd mouse, the N−1 th and the N th mouse, etc) are exactly 1. Two mice are friends if they come from the same city.

The closest friends are a pair of friends with the minimum distance. Help us find that distance.

输入

First line contains an integer T, which indicates the number of test cases.

Every test case only contains a string with length N, and the i th character of the string indicates the city of i th mice.

⋅ 1≤T≤50.

⋅ for 80% data, 1≤N≤100.

⋅ for 100% data, 1≤N≤2000.

⋅ the string only contains lowercase letters.

输出

For every test case, you should output "Case #x: y", where x indicates the case number and counts from 1 and y is the result. If there are no mice in same city, output −1 instead.

样例输入

2
abcecba
abc

样例输出

Case #1: 2
Case #2: -1

题意:找出两个相同字母的最小距离。

开一个二维数组同时记录这个字母是否出现两次和当前的位置;

距离d就是不断在上一个d和当前位置-上个位置取最小值;

如果d未改变,那么说明字母都没有出现2次,输出-1;


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1010;

int times[2][27];
char s[N];
int main(){
	int t,cas=1;
	scanf("%d",&t);
	while(t--){
		int d=N;
		memset(times,-1,sizeof(times));
		scanf("%s",s);
		for(int i=0;s[i];i++){
			times[0][s[i]-'a']++;
			
			if(times[0][s[i]-'a']){
				d=min(d,i-times[1][s[i]-'a']);
			}
			times[1][s[i]-'a']=i;
		}
		if(d==N) d=-1;
			
		printf("Case #%d: %d\n",cas++,d);
	}
	return 0;
}




问题 C: Boxes and Balls

题目描述

Tom’s friend Jerry, from KBW, just showed him a great magic trick. At the beginning of the trick, there is one box on the ground with some number of balls in it. Jerry then performs this operation over and over again: 
1. put a new empty box down on the ground 
2. move one ball from each other box into that new empty box 
3. remove any boxes that are now empty 
4. sort the boxes in nondecreasing order by the number of balls in them Tom noticed that it is possible for this operation to leave the state of the boxes and balls unchanged! 
For example:
 • Suppose that at the beginning of the trick, the one box contains 3 balls.
 • In the first operation, Jerry adds a new empty box, puts 1 ball from the existing box into it, and sorts the boxes, so after that operation, there will be 2 boxes on the ground, one with 1 ball and one with 2 balls.
 • In the second operation, Jerry adds a new empty box and puts 1 ball from each of the existing 2 boxes into it; this creates one empty box, which Jerry removes, and then he sorts the boxes. So there are 2 boxes on the ground, one with 1 ball and one with 2 balls. But this is exactly the state that was present before the second operation! 
Tom thought about the trick some more, and realized that for some numbers of balls, it is not possible for the operation to leave the state unchanged. For example, if there are 2 balls at the beginning, then after one operation, there will be two boxes with 1 ball each, and after 2 operations, there will be one box with 2 balls, and so on, alternating between these two states forever. 
Tom looked around in his room and found infinitely many empty boxes, but only N balls. What is the maximum number of those balls that he could use to perform this trick, such that one operation leaves the state unchanged? 

输入

The first line of the input gives the number of test cases, T. T lines follow. 
Each line consist of one integer N, the number of balls Tom could find. 
Limits: • 1 ≤ T ≤ 100. • 1 ≤ N ≤ 1018 .

输出

For each test case, output one line containing ‘Case #x: y’, where x is the test case number (starting from 1) and y is the maximum number of balls that Tom could use to perform the trick, as described above.  

样例输入

3
1
2
3

样例输出

Case #1: 1
Case #2: 1
Case #3: 3

题意:有N个球装在盒子里,需要对N个球进行一次操作:加入一个空盒子,把N个球所在的盒子给这个空盒子一个球,删去所有空盒子;求对N个球进行这样一次操作,与开始状态一样时的最大球数。

思路大体就是写出来找规律:最大球数=x*(x+1)/2,即当前球数范围内能求到的最大x*(x+1)/2的值;

先解出满足x*(x+1)/2=N的x,然后对x取整再带回原式即可;


#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;

int main(){
	int t,cas=1;
	ll n;
	scanf("%d",&t);
	while(t--){
		scanf("%lld",&n);
		double cmp=(sqrt(1+8*n)-1)/2.0;
		ll cmp2=(ll)cmp;
		ll ans=cmp2*(cmp2+1)/2;
	
		
		printf("Case #%d: %lld\n",cas++,ans);	
	}
}




问题 D: LCM and Walk

题目描述

Jerry has just learned some number theory, and can't wait to show his ability to Tom.

Now Jerry is sitting on a grid map of infinite rows and columns. Rows are numbered 1,2,⋯ from the bottom, so are the columns. At first Jerry is standing at grid (sx,sy), and begins his journey.

To show Tom his talents in math, he uses a special way of walk. If currently Jerry is at the grid (x,y), first of all, he will find the minimum z that can be divided by both x and y, and walk exactly z steps to the up, or to the right. So the next possible grid will be (x+z,y), or (x,y+z).

After a finite number of steps (perhaps zero), he finally finishes at grid (ex,ey). However, he is too tired and he forgets the position of his starting grid!

It will be too stupid to check each grid one by one, so please tell Jerry the number of possible starting grids that can reach (ex,ey)!

输入

First line contains an integer T, which indicates the number of test cases.

Every test case contains two integers ex and ey, which is the destination grid.

⋅ 1≤T≤1000.
⋅ 1≤ex,ey≤10 9.

输出

For every test case, you should output "Case #x: y", where x indicates the case number and counts from 1 and y is the number of possible starting grids.

样例输入

3
6 10
6 8
2 8

样例输出

Case #1: 1
Case #2: 2
Case #3: 3

题意:以(sx,sy)为起点,每次可以在右方向或上方向上移动lcm(sx,sy)步,最终到达(ex,ey)。先给定ex ey,求满足的sx sy有多少个。可以选择开始状态走0步。

每一个开始的sx sy,走到下一步时可能有2^n种情况:

直接这样看非常复杂,我们可以考虑对sx sy进行分解;

因为要用到它们的lcm,所以我们把sx=kx sy=ky lcm(sx,xy)=kxy:



因为kxy>x,kxy>y,所以从和往前逆推时,一定是大的那个数加上了lcm;如果是小的那个数加了,不应该加上lcm后还比另一个数小;

并且每次的结果一定包含k这个因子,k为sx sy的gcd;

所以我们从ex ey位置往前回推,将每次大一点数放在ey,先除去它们的gcd,得到sx sy ;如果sy能整除(x+1)则可以继续往前推,不能则说明已经得到sx sy;

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}


int main(){
	int t,cas=1;
	scanf("%d",&t);
	while(t--){
		int ans=1;
		int ex,ey;
		scanf("%d %d",&ex,&ey);
		int g=gcd(ex,ey);
		while(1){
			if(ex>ey) swap(ex,ey);
			int sx=ex/g;
			int sy=ey/g;
			if(sy%(sx+1)==0) ans++;
			else break;
			ey=sy/(1+sx)*g;
		}
		printf("Case #%d: %d\n",cas++,ans);
	}
}




问题 E: Mouse and Parenthesis

题目描述

Tom has m same balanced parenthesis sequence P=p1 p2…pn of length n.

This day Jerry comes into Tom's room and swaps one pair of parenthesis in every sequence.

Tom and Jerry both like balanced parenthesis sequence, so Jerry wants to know whether each P remains balanced after pai and pbi  swapped. 


Parenthesis sequence S is balanced if and only if:
1. S is empty;
2. or there exists balanced parenthesis sequence A,B such that S=AB;
3. or there exists balanced parenthesis sequence S' such that S=(S').

输入

The first line contains an integers T (T≤20), which indicates the number of test cases. 

For each case:

The first line contains two integers n,m.
The second line contains n characters p1 p2…pn.

The i-th of the last m lines contains 2 integers ai,bi (1≤ai,bi≤n,ai≠bi).


⋅ for 50% data, 1≤n≤50,1≤q≤1000.

⋅ for 100% data, 1≤n≤100000,1≤q≤100000.

输出

For every test case, you should output "Case #x:", where x indicates the case number and counts from 1. Then in i th line output 'Yes' if i th parenthesis sequence is balanced, otherwise 'No'. 

样例输入

2
4 2
(())
1 3
2 3
2 1
()
1 2

样例输出

Case #1:
No
Yes
Case #2:
No

题意:给一个平衡字符串,判断在每次操作后是否依然平衡;

一个字符串如果平衡,那么它的'(' ')'个数肯定是相等的,并且在出先等量的'(' ')'时,一定是'('在前;

对于两个交换的位置,两个位置字符相同时肯定Yes,')'在前'(' 在后也肯定可以,这样sum在之前一定不会小于0;

并且,交换位置对于查询区间之前和之后的sum是没有影响的;

开始的想法是让'(' =1 ')'=-1 sum记录和 平衡字符串的判定条件即sum=0且sum不会小于0;

但是每次交换都会让sum改变,重新统计和又需要遍历,考虑到只需要求特定区间的sum值改变,想到线段树;

如果直接用线段树存取则每次需要重新建树太过繁琐,因此我们考虑将sum的含义变成左右sum值的最小值;

对于一个区间,开始的'('变成 ')',sum至少要减去2,如果它的最小sum值<2,说明交换后,中间区间会<0,即无法满足题意;

查询时需要查询(i,j-1)区间,因为如果是查询至j,不知道前面的改变能否带来后面的变化(因为存的是最小值); 


#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=400010;

struct Node{
	int l,r,sum;
}tree[N];
int a[N];
char c[N];
void build(int index,int l,int r){
	tree[index].l=l;
	tree[index].r=r;
	if(l==r){
		tree[index].sum=a[l];
		return;
	}
	build(2*index,l,(r+l)/2);
	build(2*index+1,(r+l)/2+1,r);
	
	tree[index].sum=min(tree[2*index].sum,tree[2*index+1].sum);
}

int query(int index,int i,int j){
	if(tree[index].l==i&&tree[index].r==j){
		return tree[index].sum;
	}
	
	int mid=(tree[index].l+tree[index].r)/2;
	if(i>mid){
		return query(2*index+1,i,j);
	}
	else if(j<=mid){
		return query(2*index,i,j);
	}
	else{
		return min(query(2*index,i,mid),query(2*index+1,mid+1,j));
	}
}
int main(){
	int t,cas=1;
	scanf("%d",&t);
	while(t--){
		printf("Case #%d:\n",cas++);
		memset(tree,0,sizeof(tree));
		a[0]=0;
		int n,m;
	
		
		scanf("%d %d",&n,&m);
		getchar();
		for(int i=1;i<=n;i++){
			scanf("%c",&c[i]);
			if(c[i]=='(') a[i]=a[i-1]+1;
			else a[i]=a[i-1]-1;

		}
		build(1,1,n);
		int i,j;
		while(m--){
				
			scanf("%d %d",&i,&j);
			if(i>j) swap(i,j);
			if(c[i]=='('&&c[j]==')'){
//				update(1,i,-2);
//				update(1,j,2);
				if(query(1,i,j-1)>=2)  printf("Yes\n");
				else printf("No\n"); 
			}
			
			else{
				printf("Yes\n");
			
			}
			
		
			
		}
		
	}
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值