ACM一些杂题

Segment

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 18   Accepted Submission(s) : 14

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

They are N segments in x-axis. Each segment has a start point X, an end point Y, so it can be expressed as [X, Y].
Now you should select two segments, and they have the longest overlap length.
For example, segment [3, 10] and segment [7, 12] overlap in [7, 10], so the length is 3.

Input

The first line is case number T ( T <= 10 ).
For each case, the first line is the segment number N ( 1 <= N <= 100,000 ). Following there are N lines, and each line contians Xi and Yi. ( 0 <= Xi < Yi < 100,000 )

Output

The longest overlap length of any two segments.

Sample Input

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

Sample Output

4
题意:给定一些线段,求两两重叠中最大的区间。

思路:贪心,先按左区间排,然后一直往后找就可以了,复杂度O(n);

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))
const int N = 100005;

int t, n;
struct Seg {
	int l, r;
}s[N];

void init() {
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
		scanf("%d%d", &s[i].l, &s[i].r);
}

bool cmp(Seg a, Seg b) {
	return a.l < b.l;
}

int solve() {
	sort(s, s + n, cmp);
	int ans = 0, rv = s[0].r;
	for (int i = 1; i < n; i++) {
		if (s[i].r > rv) {
			ans = max(ans, rv - s[i].l);
			rv = s[i].r;
		}
		else ans = max(ans, s[i].r - s[i].l);
	}
	return ans;
}

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

Nine

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 15   Accepted Submission(s) : 4

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

Randall Munroe from xkcd.com pointed out that 9 is the most rarely used key on a microwave. Let‘s all share the load.

Given a desired cooking time, find a sequence of keys with the greatest number of 9‘s such that the resulting time has less than 10% error compared to the desired cooking time. In other words, if T is the desired cooking time in seconds, and T9 is the cooking time specified by the found sequence, then 10|T - T9| < T. If there are multiple possibilities, choose the one that has the smallest error (in magnitude). If there are still ties, choose the one that is lexicographically smallest.

For example, for T = 01:15, the times 00:68-00:82 and 1:08-1:22 have less than 10% error. Of these, 00:69, 00:79, 01:09, and 01:19 have the greatest number of 9‘s, and the ones with the smallest error are 00:79 and 01:19. The lexicographically smaller of these is 00:79.

Input

The input consists of a number of cases. For each case, the desired cooking time in MM:SS format is specified on one line. Each M or S can be any digit from 0 to 9. The end of input is indicated by 00:00.

Output

For each case, output on a single line the four keys to use as input to the microwave, in MM:SS format.

Sample Input

00:30
01:00
02:00
91:30
46:03
00:00

Sample Output

00:29
00:59
01:59
90:99
49:99
题意:给定一个时间,找出误差时间在10%以内, 9最多, 误差时间最少, 字典序最小的时间
思路:直接暴力4个数字找出最合适的即可。复杂度O(10^4)
代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define INF 0x3f3f3f3f
char str[10];

int Sum(int *num) {
	int sum = (num[0] * 10 + num[1]) * 60 + (num[2] * 10 + num[3]);
	return sum;
}

struct Ans {
	char str[5];
	int num[4];
	int nine;
	int d;
}ans;

void solve() {
	int num[4];
	ans.nine = 0; ans.d = INF;
	memset(ans.str, 0, sizeof(ans.str));
	strcpy(ans.str, "9999");
	num[0] = str[0] - ‘0‘; num[1] = str[1] - ‘0‘; num[2] = str[3] - ‘0‘; num[3] = str[4] - ‘0‘;
	int sum = Sum(num);
	for (num[0] = 0; num[0] < 10; num[0]++)
		for (num[1] = 0; num[1] < 10; num[1]++)
			for (num[2] = 0; num[2] < 10; num[2]++)
				for (num[3] = 0; num[3] < 10; num[3]++) {
					int s = Sum(num);
					if (10 * abs(sum - s) >= sum) continue;
					int dd = abs(sum - s);
					int nine = 0;
					for (int i = 0; i < 4; i++)
						if (num[i] == 9) nine++;
					if (nine >= ans.nine) {
						if (nine == ans.nine) {
							if (dd <= ans.d) {
								if (dd == ans.d) {
									char ss[5];
									for (int k = 0; k < 4; k++)
										ss[k] = num[k] + ‘0‘;
									ss[4] = ‘\0‘;
									if (strcmp(ss, ans.str) < 0) {
										ans.nine = nine;
										for (int j = 0; j < 4; j++) {
											ans.num[j] = num[j];
											ans.str[j] = num[j] + ‘0‘;
									}
									ans.d = dd;
									}
								}
								else {
									ans.nine = nine;
									for (int j = 0; j < 4; j++) {
										ans.num[j] = num[j];
										ans.str[j] = num[j] + ‘0‘;
									}
									ans.d = dd;
								}
							}
						}
						else {
							ans.nine = nine;
							for (int j = 0; j < 4; j++) {
								ans.num[j] = num[j];
								ans.str[j] = num[j] + ‘0‘;
							}
							ans.d = dd;
						}
					}
				}
	printf("%d%d:%d%d\n", ans.num[0], ans.num[1], ans.num[2], ans.num[3]);
}

int main() {
	while (gets(str) != NULL) {
		if (str[0] == ‘0‘ && str[1] == ‘0‘ && str[3] == ‘0‘ && str[4] == ‘0‘) break;
		solve();
	}
	return 0;
}

搞笑版费马大定理

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 20   Accepted Submission(s) : 14

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

费马大定理:当n>2时,不定方程a^n+b^n=c^n没有正整数解。比如a^3+b^3=c^3没有正整数解。为了活跃气氛,我们不妨来个搞笑版:把方程改成a^3+b^3=c3,这样就有解了,比如a=4, b=9, c=79时4^3+9^3=793。
输入两个整数x, y, 求满足x<=a,b,c<=y的整数解的个数。

Input

输入最多包含10组数据。每组数据包含两个整数x, y(1<=x,y<=10^8)。

Output

对于每组数据,输出解的个数。

Sample Input

1 10
1 20
123 456789

Sample Output

Case 1: 0
Case 2: 2
Case 3: 16

思路:暴力枚举,枚举a,b只要枚举到a^3<=y*10+3, a^3+b^3<=y*10+3。然后c去计算出来。复杂度O((y*10)^2/3)
代码:
#include <stdio.h>
#include <string.h>

int x, y, ans, fuck;

int solve() {
	ans = 0; fuck = 0;
	for (int i = x; i * i * i <= y * 10 + 3; i++)
		for (int j = i; i * i * i + j * j * j <= y * 10 + 3; j++) {
			int sum = ((i * i * i + j * j * j) - 3);
			if (sum % 10) continue; sum /= 10;
			if (sum >=x && sum <= y) {
				if (x == y) fuck++;
				ans++;
			}
		}
	return ans * 2 - fuck;
}

int main() {
	int cas = 0;
	while (~scanf("%d%d", &x, &y)) {
		printf("Case %d: %d\n", ++cas, solve());
	}
	return 0;
}

Max Sum

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 62   Accepted Submission(s) : 13

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

There are N intergers make up a loop. Your job is to calculate the max sum of consecutive sub-suquence in the loop. Note, you can select a null consecutive sub-suquence.
For example, given (3, 1, -5, 2), the max sum is 2+3+1 = 6.

Input

The first line of the input contains an integer T (1<=T<=50) which means the number of est cases. Then T lines follow, and each line starts with a number N (1<=N<=100,000), then N integers followed (all the integers are between -1,000 and 1,000).

Output

For each test case, you should output one integers, the max sum.

Sample Input

3
4
3 1 -5 2
2
-4 -1
5
3 -1 4 -4 -2

Sample Output

6
0
6
题意:求环状序列最大子序列和。
思路:单调队列去维护sum[i]最小值,sum[j] - sum[i](j - i <= n)最大的为答案,.复杂度O(n)
代码:
#include <stdio.h>
#include <string.h>
#include <queue>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;

const int N = 200005;

int t, n, num[N];
struct Node {
	int sum, id;
}s[N];

void init() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &num[i]);
		num[i + n] = num[i];
	}
}

int solve() {
	int ans = 0;	
	s[0].sum = 0; s[0].id = 0;
	deque<Node>Q;
	Q.push_front(s[0]);
	for (int i = 1; i <= 2 * n; i++) {
		s[i].sum = s[i - 1].sum + num[i];
		s[i].id = i;
		while (!Q.empty() && Q.back().sum >= s[i].sum) {Q.pop_back();}
		while (!Q.empty() && s[i].id - Q.front().id > n) {Q.pop_front();}
		Q.push_back(s[i]);
		ans = max(ans, s[i].sum - Q.front().sum);
	}
	return ans;
}

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

Find the max Link

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 12   Accepted Submission(s) : 5

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

由N个点组成的无向图,每条边有对应的权值,保证每两点之间存在且仅存在一条路径,一条路径的权值为其所有边的权值之和,请找出一条路径,对于图中每个点至多经过一次,并且这条路径上至少有一条边,这条路径的权值最大。

Input

多组数据(至多30组),第一行两个正整数N,M(2<=N<=50000,1<=M<=50000),接下来M行,每行三个整数U,V,W(1<=U,V<=N,-100000<=W<=100000)代表在点V,W间有一条权值为W的边。

Output

每组数据输出一行,为一个整数即满足题目要求的路径权值。

Sample Input

4 3
3 1 -1
4 2 4
2 1 5

Sample Output

9

思路:树形DP,dp[u][0]代表第一大的路径,dp[u][1]代表第二大的路径,复杂度o(m)
代码:
#include <stdio.h>
#include <string.h>
#include <vector>
#define max(a,b) ((a)>(b)?(a):(b))
#define INF 0x3f3f3f3f
using namespace std;

const int N = 50005;

int n, m, ans, dp[N][2];
struct Node {
	int v, value;
	Node(int vv, int va) {
		v = vv; value = va;
	}
};
vector<Node>g[N];

void init() {
	int u, v, value;
	ans = -INF;
	memset(g, 0, sizeof(g));
	for (int i = 0; i < m; i++) {
		scanf("%d%d%d", &u, &v, &value);
		ans = max(ans, value);
		g[u].push_back(Node(v, value));
		g[v].push_back(Node(u, value));
	}
}

void dfs(int u, int fa) {
	dp[u][0] = dp[u][1] = -INF;
	for (int i = 0; i < g[u].size(); i++) {
		int v = g[u][i].v, value = g[u][i].value;
		if (fa == v) continue;
		dfs(v, u);
		int t = 0;
		if (dp[v][0] > 0) t = dp[v][0];
		if (dp[u][0] < t + value) {
			dp[u][1] = dp[u][0];
			dp[u][0] = t + value;
		}
		else if (dp[u][1] < t + value)
			dp[u][1] = t + value;

	}
	ans = max(ans, dp[u][0]);
	ans = max(ans, dp[u][0] + dp[u][1]);
}

int main() {
	while (~scanf("%d%d", &n, &m)) {
		init();
		dfs(1, 0);
		printf("%d\n", ans);
	}
	return 0;
}

Sum

Time Limit : 10000/5000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 17   Accepted Submission(s) : 8

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

Given a sequence a [1], a [2], a [3]......a[n], your job is to calculate how many sub-sequence whose summation is equal to SUM.

We define a sub-sequence of the sequence is a[i],a[i+1]...a[j-1],a[j] ( i <= j ).And the number of this sub-sequence is j-i+1.

Input

The first line of the input contains an integer T (1<=T<=10) which means the number of test cases. Then T lines follow, each line starts with a number N (1<=N<=100000) and a integer sum, then N integers followed (all the integers are between 0 and 1000).

Output

For each test case, you should output one line. The line is a number about how many sub-sequences whose summation is equal to SUM.

Sample Input

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

Sample Output

2
1
6
题意:求一个序列中子序列和为sum的个数。
思路:two pointer,注意0的情况。要记录从h开始到r有多少个前缀的0.
代码:
#include <stdio.h>
#include <string.h>

const int N = 100005;
int t, n, sum, num[N];

void init() {
	scanf("%d%d", &n, &sum);
	for (int i = 0; i < n; i++)
		scanf("%d", &num[i]);
}

int solve() {
	int h = 0, r = 0, s = 0, ans = 0;
	while (r < n) {
		s += num[r];
		if (s > sum) {
			while (s > sum) {s -= num[h++];}
		}
		if (s == sum) {
			int cal = 1;
			for (int i = h; i < r; i++) {
				if (num[i] == 0) cal++;
				else break;
			}
			ans += cal;
		}
		r++;
	}
	return ans;
}

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

寻找acm

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 27   Accepted Submission(s) : 13

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

作为一个acmer,应该具备团队合作能力和分析问题能力。给你一个只有a,c和m的字符串,你要依次取3个字母使之恰好为acm。 
比如串 
accmmmca 你可以取 
12345678 
ac_m____ 
ac__m___ 
ac___m__ 
a_cm____ 
a_c_m___ 
a_c__m__共6种。 

你只要给出给你的串有多少种方案能组成acm。

Input

一个只有acm3种字母的串(长度<=2000)

Output

一个整数一行,表示给你的串有多少种方案能组成acm。

Sample Input

accmmmca

Sample Output

6
思路:dp,dp[i][j]表示s长度为i在str长度为j的时候有几个。
代码:
#include <stdio.h>
#include <string.h>

const int N = 2005;
const char s[4] = {"acm"};

char str[N];
long long dp[4][N];

long long DP() {
	int len = strlen(str + 1);
	for (int k = 0; k <= len; k++)
		dp[0][k] = 1;
	for (int i = 1; i <= 3; i++) {
		dp[i][0] = 0;
		for (int j = 1; j <= len; j++) {
			if (str[j] == s[i - 1]) {
				dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1];
			}
			else {
				dp[i][j] = dp[i][j - 1];
			}
		}
	}
	return dp[3][len];
}

int main() {
	while (gets(str + 1) != NULL) {
		printf("%lld\n", DP());
	}
	return 0;
}

Shooting Game

Time Limit : 6000/2000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 8   Accepted Submission(s) : 4

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

Fat brother and Maze are playing a kind of special (hentai) game in the playground. (Maybe it’s the OOXX game which decrypted in the last problem, who knows.) But as they don’t like using repellent while playing this kind of special (hentai) game, they really suffer a lot from the mosquito. So they decide to use antiaircraft gun to shoot the mosquito. You can assume that the playground is a kind of three-dimensional space and there are N mosquitoes in the playground. Each of them is a kind of point in the space which is doing the uniform linear motion. (匀速直线运动) Fat brother is standing at (0, 0, 0) and once he shoot, the mosquito who’s distance from Fat brother is no large than R will be shot down. You can assume that the area which Fat brother shoot is a kind of a sphere with radio R and the mosquito inside this sphere will be shot down. As Fat brother hate these mosquito very much, he wants to shoot as much mosquito as he can. But as we all know, it’s tired for a man to shoot even if he is really enjoying this. So in addition to that, Fat brother wants to shoot as less time as he can.

You can (have to) assume that Fat brother is strong enough and he don’t need to rest after shooting which means that can shoot at ANY TIME.

Input

The first line of the date is an integer T, which is the number of the text cases.

Then T cases follow, each case starts with two integers N and R which describe above.

Then N lines follow, the ith line contains six integers ax, ay, az, dx, dy, dz. It means that at time 0, the ith mosquito is at (ax, ay, az) and it’s moving direction is (dx, dy, dz) which means that after time t this mosquito will be at (ax+dx*t, ay+dy*t, ax+dz*t). You can assume that dx*dx + dy*dy+ dz*dz > 0.

1 <= T <= 20, 1 <= N <= 100000, 1 <= R <= 1000000

-1000000 <= ax, ay, az <= 1000000

-100 <= dx, dy, dz <= 100

The range of each coordinate is [-10086, 10086]

Output

For each case, output the case number first, then output two numbers A and B.

A is the number of mosquito Fat brother can shoot down.

B is the number of times Fat brother need to shoot.

Sample Input

6
2 1
2 0 0 -1 0 0
-2 0 0 1 0 0
2 1
4 0 0 -1 0 0
-2 0 0 1 0 0
2 1
4 0 0 -1 0 0
1 0 0 1 0 0
2 1
1 1 1 1 1 1
-1 -1 -1 -1 -1 -1
1 1
0 0 0 1 0 0
3 1
-1 0 0 1 0 0
-2 0 0 1 0 0
4 0 0 -1 0 0

Sample Output

Case 1: 2 1
Case 2: 2 1
Case 3: 2 2
Case 4: 0 0
Case 5: 1 1
Case 6: 3 2

本质上就是个贪心的区间选点问题,不过区间要先算出来。
代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int N = 100005;

struct Point {
	double x, y, z;
	double xk, yk, zk;
	double s, e;
	int vis;
} p[N];

int t, n, ansn, ansc;
double r;

void init() {
	ansn = ansc = 0;
	memset(p, 0, sizeof(p));
	scanf("%d%lf", &n, &r);
	for (int i = 0; i < n; i ++) {
		scanf("%lf%lf%lf%lf%lf%lf", &p[i].x, &p[i].y, &p[i].z, &p[i].xk, &p[i].yk, &p[i].zk);
	}
}

bool cmp(Point a, Point b) {
	return a.e < b.e;
}
void solve() {
	ansn = n;
	for (int i = 0; i < n; i ++) {
		double a = p[i].xk * p[i].xk + p[i].yk * p[i].yk + p[i].zk * p[i].zk;
		double b = 2 * p[i].x * p[i].xk + 2 * p[i].y * p[i].yk + 2 * p[i].z * p[i].zk;
		double c = p[i].x * p[i].x + p[i].y * p[i].y + p[i].z * p[i].z - r * r;
		double dlt =b * b - 4 * a * c;
		if (dlt < 0) {
			ansn--;
			continue;
		}
		double k1 = (-b + sqrt(dlt)) / (2 * a);
		double k2 = (-b - sqrt(dlt)) / (2 * a);
		if (k1 < 0 && k2 < 0) {
			ansn--;
			continue;
		}
		if (k2 < k1) {
			if (k2 < 0) k2 = 0;
			p[i].s = k2; p[i].e = k1;
		}
		else {
			if (k1 < 0) k1 = 0;
			p[i].s = k1; p[i].e = k2;
		}
		p[i].vis = 1;
	}
	sort(p, p + n, cmp);
	double c = -1000000000;
	for (int ii = 0; ii < n; ii ++) {
		if (!p[ii].vis) continue;
		if (p[ii].s > c) {
			c = p[ii].e;
			ansc ++;
		}
	}
}

int main() {
	int cas = 0;
	scanf("%d", &t);
	while (t--) {
		init();
		solve();
		printf("Case %d: %d %d\n", ++cas, ansn, ansc);
	}
	return 0;
}


ACM一些杂题

上一篇:两个Xcode主题:Railscasts和Zenburn


下一篇:如何更有效的调试运行MATLAB程序(阅读)