2016寒假训练赛(二)自我总结

时间:2017年1月20日 13:00 ~· 17:00

总结:全场挂机,A了三道签到题,另外有三题都是以前了解过的知识点,然而我是比赛结束后才发现原来这么简单

这一场又暴露出了读题不仔细和几大知识体系的缺陷。

一.STL模板中String的不熟悉。

二.同余定理熟练度不够。

.......(其余知识点将在题解中补充)


题目:1001

Balloon MM is coming

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 41   Accepted Submission(s) : 40
Font: Times New Roman | Verdana | Georgia
Font Size:  

Problem Description

There is an interesting rule in acm-game, that is, if you work out a problem, a pretty MM will come to give you a balloon as a present. Now, this problem is for you to get a balloon.

Input

The first line of the input is an integer T, which means there are exactly T cases in the input.Each test case contains an integer N (1<=N<=1000) which means there are N numbers.The second line comes N numbers seperated by a single whitespace.
Your task is to output one integer. It equals to the result of all the even integers minus the odd ones among those given N integers.

Output

For each test case, you should output the answer in a single line. 

Sample Input

2
3
1 2 3
4
1 2 3 4

Sample Output

-2
2


签到题,大意是统计n个数中的偶数和减去奇数和的结果,输入时预处理统计,然后直接做差即可
(因为没说数据范围,保险起见用了long long)
#include <bits/stdc++.h>
using namespace std;

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		long long n,sum1,sum2,i,x;
		scanf("%lld",&n);
		sum1 = sum2 = 0;
		for(i=1 ;i<=n ;i++){
			scanf("%lld",&x);
			if(x%2)
				sum1 += x;
			else
				sum2 += x;
		}
		printf("%lld\n",sum2-sum1);
	}
	return 0;
}

1002:

A * B Problem

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 126   Accepted Submission(s) : 34
Font: Times New Roman | Verdana | Georgia
Font Size:  

Problem Description

Welcome to the contest. I'm sure you all have solved "a + b" problems in HDOJ. Now, an "a * b" problem comes to you. I think "a * b" is updated from "a + b" because "a * b" can be calculated in additions. Now, please Calculate (A * B) % C.

Input

The first line of the input is an integer T, which means there are exactly T cases in the input.Each cases will contain three integers A , B and C(0<=A, B, C<=10 ^ 15 , C>0).

Output

For each case, output (A * B) % C in one line.

Sample Input

1
2 3 4

Sample Output

2

Hint

1. I advise you to read the data like "scanf("%I64d", &a) ", and indicate the integers in the format as "__int64 a;", because the "int" range from -2 ^ 31 to 2 ^ 31 - 1.
2. Note the data range.
3. There is a algorithm called Russian peasant algorithm. I think it may help you to ac(or say solve) this problem. For example, we are to calculate 77 * 33(you can find something in this example).
a b 
77 33 
38 66 +33
19 132 
9 264 +132
4 528 +264
2 1056 
1 2112

So the result is 2112 + 264 + 132 + 33 = 2541

Source

计算机学院大学生程序设计竞赛(2011’10)(外校勿注册)

开始模拟题目下面的算法写,结果因为有一个需要一直乘2的数(如例子中的b:33->66->...->2112)
调试了一下哪怕是unsigned __int64也会爆,然后写了一个高精度,用两个数组分别存b和最终的结果,
结果正确了但忽然想起题目还要求取余qwq,高精度取余....没思路,难道要我一项项按权相加再取余??
所以又只有重写,最终浪费了很多时间才AC。
知识点总结:(a+b),(a-b),(a*b)对c取模均可以拆项分别取余,在递推和矩阵快速幂中有着重要应用。(a/b不行)。
拓展:
(1).九余数定理:一个数的每位数字之和等于这个数对9取余,如果等于0就是9。
(2).同余定理及包括中国剩余定理在内的性质。
代码:
#include <bits/stdc++.h>
using namespace std;

const int maxn = 1001;

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		long long a,b,c,ans;
		scanf("%I64d%I64d%I64d",&a,&b,&c);
		if(a<b)
			swap(a,b);    //让小的数做乘法,大的数做加法 
		ans = 0;
		while(a>0){
			if(a&1){               //如果a为奇数。 
				ans += (b%c);
			}
			a /= 2;
			b = b*2%c;
		}
		ans %= c;
		printf("%I64d\n",ans);
	}
	return 0;
}

1003:

62-system number

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 146   Accepted Submission(s) : 22
Font: Times New Roman | Verdana | Georgia
Font Size:  

Problem Description

Recently, Tom did a research in 62-system number(0~9,A~Z,a~z mean 0~9, 10~35, 36~61 respectively). He wrote two 62-system numbers in two cards and asked bb and dd to choose one, dd always choose the first. Each of them can rotate the number to make the number minimum. ( after abc is rotated, the string changes like(abc->cab->bca->abc), certainly bb and dd will choose the smallest one )
The one that gets the smaller number wins. 

Input

The first line of the input is an integer T, which means there are exactly T cases in the input.
Each test case contain two strings(the first is the number dd chose , both are shorter than 10001)

Output

If dd wins output"dd", and if bb wins outputs "bb", otherwise outputs "ddbb".

Sample Input

1
0aab0
00aac

Sample Output

dd

题目意思很简单,也有一些想法,但因为感觉自己的想法时间复杂度挺高(但赛后讨论了一下发现真有想法相同而且过掉的人qwq)并且做后面的题卡住了没时间尝试,
赛后听朱神的讲解+下面的博客渐渐懂了这道题:
http://blog.csdn.net/cclsoft/article/details/5467743
所以解法一:找到字符串同构的最小表示法,然后比较就ok。
解法二:利用STL模板的string(参考大神的代码)
代码一:15ms
#include <bits/stdc++.h>
using namespace std;

const int maxn = 50001;
char s1[maxn],s2[maxn];

int Min_pos(char* str){
	int len = strlen(str);
	int i=0,j=1,k=0;
	while(i<len && j<len && k<len){  
		int tem = str[(i+k)%len] - str[(j+k)%len];
		if(!tem)
			k++;
		else{
			if(tem<0){
				j = j + k + 1;
			}
			else{
				i = i + k + 1;
			}
			if(i==j)
				++j;
			k = 0;
		} 	
	}
	return min(i,j);
}

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%s%s",s1,s2);
		int p1 = Min_pos(s1), len1 = strlen(s1);
		int p2 = Min_pos(s2), len2 = strlen(s2);
		//cout << p1  << " " << p2 << endl;
		int k = 0,maxlen = max(len1,len2);
		while(s1[(p1+k)%len1] == s2[(p2+k)%len2] && k<=maxlen){
			k++;
		}
		if(s1[(p1+k)%len1] > s2[(p2+k)%len2]){
			printf("bb\n");
		}
		else if(s1[(p1+k)%len1] < s2[(p2+k)%len2]){
			printf("dd\n");
		}
		else{
			printf("ddbb\n");
		}
	}
	return 0;
}
代码二:550ms
#include <bits/stdc++.h>
using namespace std;

const int maxn = 50001;
string s1,s2,s3,s4,s5,s6;
char str[maxn];

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%s",str);
		s1.assign(str);
		scanf("%s",str);
		s2.assign(str);
		int len1 = s1.size(),len2 = s2.size();
		int len = min(len1,len2);      
		s3 = s1;
		s4 = s2;            //保存原来的字符串
		s1 = s1 + s1;
		s2 = s2 + s2;       //将字符串首尾相连,方便取子串	
		for(int i=0 ;i<len ;i++){
			s5 = s1.substr(i,len);  //取s1下标为i的元素开始,长度为len的子串 
			s6 = s2.substr(i,len);
			if(s5 < s3)
				s3 = s5;
			if(s6 < s4)
				s4 = s6; 
		}
		//cout << s3 << " " << s4 << endl;
		if(s3 < s4){
			printf("dd\n");
		} 
		else if(s3 > s4){
			printf("bb\n");
		}
		else{
			printf("ddbb\n");
		}
	}
	return 0;
}
题目1004:

Ball Game

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 36   Accepted Submission(s) : 15
Font: Times New Roman | Verdana | Georgia
Font Size:  

Problem Description

Watano is a very clear boy. One day, he plays a game with his friends. There are K kinds of balls.
At first, each friend has some amount of resources for each kind. The rules of the game are as follows:
1. For each friend A of Watano’s, if A has fewer balls for each kind than Watano, A will give all the balls to Watano, otherwise, nothing will happen.
2. If no friends meeting the condition above then exit, game will be over.
Now, Watano wants you, a clever acmer, tell him how many balls for each kind he will get at last.

Input

There are three parts in the input.
The first part contains two integers N (1<= N <= 10000) and K (1<= K <= 10) representing the number of friends and the number of kinds of the balls.
The second part contains one line. There are K numbers in a line, c1, c2, c3…cK. ci represents the amounts of ith ball Watano has.
The third part contains a N * K matrix. The Matrix[i][j](0 <= i < N, 0 <= j < K, 0<= Matrix[i][j] <= 1000) represents the amounts of jth ball the ith friend has.

Output

There is only one part in the output.
There are K integers in a line, c1, c2…cK, representing how many balls for each kind Watano gets at last.

Sample Input

1 2 
2 2 
1 2 
	
1 2 
2 2 
1 1 

2 2 
5 5  
2 5  
1 1

Sample Output

2 2 
3 3 
8 11 

Source

计算机学院大学生程序设计竞赛(2011’10)(外校勿注册)

虽然学了一上午的拓扑排序,但因为一些基础的C++知识没有掌握,理解了朱神的思路,却仍然看不懂实现的具体方式,所以自己试着写了一个暴力330ms水过,另外将朱神的代码贴在这,等以后知识储备足够了再来研究。
暴力:
#include <bits/stdc++.h>
using namespace std;

const int maxn = 10001;
int f[maxn][15],a[15];

int main(){
	int n,k;
	bool flag;
	while(scanf("%d%d",&n,&k) != EOF){
		int i,j;
		for(i=0 ;i<k ;i++)
			scanf("%d",&a[i]);
		for(i=0 ;i<n ;i++){
			flag = 1;
			for(j=0 ;j<k ;j++){
				scanf("%d",&f[i][j]);
				if(f[i][j] >= a[j])
					flag = 0;
			}
			if(flag){
				for(j=0 ;j<k ;j++){
					a[j] += f[i][j];
					f[i][j] = -1;
				}
			}
		}
		for(i=0 ;i<n ;i++){
			flag = 1;
			for(j=0 ;j<k ;j++){
				if(f[i][j] == -1 || f[i][j] >= a[j]){
					flag = 0;
					break;
				}
			}
			if(flag){
				for(j=0 ;j<k ;j++){
					a[j] += f[i][j];
					f[i][j] = -1;
				}
				i = 0;
			}
		}
		printf("%d",a[0]);
		for(i=1 ;i<k ;i++){
			printf(" %d",a[i]);
		}	
		printf("\n");
	}
	return 0;
} 


类拓扑排序:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
template <class T>
inline void scan(T &ret) {
    char c; ret=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}
int n,K;
int d[10005][11];
int cnt[10005];
struct Pair{
    Pair(){}
    Pair(int a,int b):val(a),idx(b){}
    int val,idx;
    bool operator<(const Pair&b)const{
        return val<b.val;
    }
}p[11][10005];
int pt[11];
int main(){
    while(~scanf("%d%d",&n,&K)){
        for(int i=0;i<K;i++)scan(d[0][i]);
        for(int i=1;i<=n;i++){
            cnt[i]=0;
            for(int j=0;j<K;j++){
                scan(d[i][j]);
                p[j][i-1]=Pair(d[i][j],i);
            }
        }
        for(int j=0;j<K;j++)sort(p[j],p[j]+n);
        queue<int> q;
        memset(pt,0,sizeof(pt));
        for(int j=0;j<K;j++){
            while(pt[j]<n&&p[j][pt[j]].val<d[0][j]){
                int y=p[j][pt[j]].idx;
                cnt[y]++;
                if(cnt[y]==K)q.push(y);
                pt[j]++;
            }
        }
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int j=0;j<K;j++)d[0][j]+=d[x][j];
            for(int j=0;j<K;j++){
                while(pt[j]<n&&p[j][pt[j]].val<d[0][j]){
                    int y=p[j][pt[j]].idx;
                    cnt[y]++;
                    if(cnt[y]==K)q.push(y);
                    pt[j]++;
                }
            }
        }
        for(int j=0;j<K;j++){
            printf(j==K-1?"%d\n":"%d ",d[0][j]);
        }
    }
    return 0;
}




题目1005:

Distinct Number

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 60   Accepted Submission(s) : 40
Font: Times New Roman | Verdana | Georgia
Font Size:  

Problem Description

Believe me, this is a very easy task. 
Given n integers, you are just to select as many numbers as you can, and these numbers should be distinct from each other.

Input

The first line of the input is an integer T, which means there are exactly T cases in the input.Each test case contains an integer N ( 0<= N <= 1000),then follow N integers (-10 ^ 9 <= a[i] <= 10 ^ 9).

Output

For each case, output the maximum amount of integers you can select in a line. 

Sample Input

3
2 3 4
3 2 2 4
3 1 2 3

Sample Output

2
2
3

Source

计算机学院大学生程序设计竞赛(2011’10)(外校勿注册)

签到水题。
#include <bits/stdc++.h>
using namespace std;

map<int,int> mp;

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,sum,i,x;
        scanf("%d",&n);
        sum = 0;
        mp.clear();
        for(i=0 ;i<n ;i++){
            scanf("%d",&x);
            if(!mp[x]){
                sum++;
                mp[x] = 1;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}

题目 1006:

Matrix appears

Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 28   Accepted Submission(s) : 10
Font: Times New Roman | Verdana | Georgia
Font Size:  

Problem Description

Give you a big matrix and many small matrix . Now I want to know how many times each small matrix appears in the big matrix. We consider that a small matrix appears in big matrix only if the big matrix's submatrix is equal to the small matrix . A matrix is equal to another matrix means the two matrixes are exactly same.
The small matrix will always have 3 rows and 3 columns. And it's left top and right top will always be a '*' (which can become any characters if you want). The rest position only contain characters from '0' to '9'.

Input

The beginning of the input is an integer T (T <= 321), which is the number of test cases. The first line of each test case is two integers n and m(the size of big matrix). ( 0 < n , m < 100 ). Followed by n lines each with m characters (only contain '0' - '9'). Then followed by a integer Q (0 < Q <= 321). Followed by Q small matrixes . There are a blank line after each small matrixes.

Output

For each case output the format like Case x: ( x start from 1).For each small matrix, please output how many times it appears in the big matrix.

Sample Input

3
3 3
123
456
789
2
*2*
456
789

*2*
455
789

4 4
1111
1111
1111
1111
1
*1*
111
111

3 4
3115
1111
1211
3
*1*
111
211

*1*
111
121

*2*
111
121

Sample Output

Case 1:
1
0
Case 2:
4
Case 3:
1
1
0

Source

看了朱神的题解,思路秒懂,自己试着写了但时间复杂度偏高,后来了解了upper_bound,lower_bound和binary_search三个函数,有了一些优化的思路,代码先不贴了,等好久又有重现赛时提交了AC再贴。


题目1007:

Mini_cost

Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 65   Accepted Submission(s) : 22
Font: Times New Roman | Verdana | Georgia
Font Size:  

Problem Description

There are Y lines parallel to x axis. And there are exactly n number of point in each lines. Now wanwan want to move these point in lines which is parallel to y axis. And exactly n lines totaly. And for each point (x,y) , only the value of x can be changed. And no two point can in the same position. Move a point (x, y) to (x', y) cost abs(x' - x) . Now wanwan want to know the minimum of the total cost to finish the job. 

Input

The first line of the input is an integer T, which means there are exactly T cases in the input.
For each test , the first line contain tow integers Y , n(0<Y ,n< 1000), and follow Y lines , every line contain n integers , the jth integer x[ i ][ j ] represent the x_axis of the jth point in the ith line(abs( x[i][j]) < 1000000 )

Output

For each case, output the minimum of the total cost to finish the job. 

Sample Input

1
3 3
1 2 3
1 3 4
0 1 2

Sample Output

5


英语不好, x_axis在此处原来是横坐标的意思,之前一直翻译成X轴,然后将j与纵坐标对应了.....思路是对的,但输入的横纵坐标整反了,另外直线上n个点到某一点的距离最短,改点应该是横坐标的中位数而不应该是平均数,当时WA太多,后期将往平均数的方向改,结果WA到崩溃。由此可知认真读题的重要性!!!
代码:
#include <bits/stdc++.h>
using namespace std;

const int maxn = 1000 + 10;
int p[maxn][maxn];

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int y,n,i,j;
		scanf("%d%d",&y,&n);
		for(j=0 ;j<y ;j++){
			for(i=0 ;i<n ;i++){
				scanf("%d",&p[i][j]);
			}
		}
		long long ans = 0;
		for(i=0 ;i<n ;i++){
			sort(p[i],p[i]+y);
			int t = p[i][y/2];
			for(j=0 ;j<y ;j++){
				ans += abs(p[i][j] - t);
			}
		}	
		printf("%lld\n",ans);
	}
	return 0;
} 

题目1008:

Necklace

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 98   Accepted Submission(s) : 22
Font: Times New Roman | Verdana | Georgia
Font Size:  

Problem Description

Recently,Tom is infatuated with necklaces. Once he see a necklace, he can't solve acm problems. He bought C kinds of beads to make necklaces, every kind of beads is infinite(Yes, it's true).Now he wants to make a necklace with length R, and he is wondering how many kinds of necklaces he can make. Let's see how Tom define the kind of necklace: if necklace A has at least one beads which is not belong to necklace B, then A is different from B.
Here is a example: "aabc", "abcc", "abcd", the first one is same to the second, but the third one is different from others.Now, Tom asks you for help, just help him to calculate the kinds.

Input

The first line of the input is an integer T, which means there are exactly T cases in the input. Follow T lines , each case one line , Each case contains two numbers C, R ( 0< R<= C< 100). 

Output

For each case, output the kinds of necklace mod by 1000007.

Sample Input

1
3 3

Sample Output

7

Source

计算机学院大学生程序设计竞赛(2011’10)(外校勿注册)
这道题又让我深刻意思到了自己学习方法上出了问题,组合数结合杨辉三角来解的题我是做过,并且专门把这个知识点存在了我的ACMword文档里面。但做题时的迷之状态让我一直在解决算大的组合数结果溢出的问题,然后wa了十发orz。
杨辉三角的性质:第n行的m个数可表示为  C(n-1,m-1) ,即为从n-1个不同元素中取m-1个元素的组合数。
代码:
#include <bits/stdc++.h>
using namespace std;

const int maxn = 100 + 10;
const int mod = 1000007;
int a[maxn][maxn];

void init(void){
	int i,j;
	memset(a,0,sizeof(a));
	for(i=1 ;i<maxn ;i++){
		for(j=1 ;j<=i ;j++){
			if(j==1 || j==i)
				a[i][j] = 1;
			else
				a[i][j] = (a[i-1][j] + a[i-1][j-1])%mod;
		}
	}
}

void solve(int m,int n){
	int i,ans = 0;
	for(i=2 ;i<=m+1 ;i++){
		ans = (ans + a[n+1][i])%mod;
	}
	printf("%d\n",ans);
}

int main(){
	int T;
	scanf("%d",&T);
	init();
	while(T--){
		int m,n;
		scanf("%d%d",&n,&m);
		solve(m,n);
	}
	return 0;
} 

题目1009:

Number Problem

Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 92   Accepted Submission(s) : 14
Font: Times New Roman | Verdana | Georgia
Font Size:  

Problem Description

Given an integer N, we define an equation like this: N=a[1]+a[2]+a[3]+...+a[m]; a[i]>0, 1 <= m <= N; My question is how many different equations you can find for a given N.For example, assume N is 3, we can find 4 equations: 3 = 1 + 1 + 1; 3 = 1 + 2; 3 = 2 + 1; 3 = 3.So the result is 5 when N is 4. Note that "4 = 3 + 1" and "4 = 1 + 3" are different in this problem. The answer is so big, so I only want to know the number of different equations & p( & is the bitwise operator AND).

Input

The input contains several test cases. Each test case contains two integers N (N <= 2^63 - 1) and p (0 <= p <= 2^63 - 1). The input is terminated by the end of file.

Output

For each test case, you have to output the answer in a line.

Sample Input

2 2
3 4

Sample Output

2
4
听了朱神的讲解豁然开朗,此题秒变水题,但因为没注意到N可以取负数,然后还是WA了几发。
#include <bits/stdc++.h>
using namespace std;

int main(){
	__int64 n,p,ans;
	while(scanf("%I64d%I64d",&n,&p) != EOF){
		if(n<=0 || n>=64){
			printf("0\n");
		}
		else{
			printf("%I64d\n",((1LL<<(n-1))&p));
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值