水题(5)计算题

目录

CSU 1035 Max DPS

CSU 1040 Round-number

CSU 1042 遥控机器人

CSU 1114 平方根大搜索

CSU 1131 Nim-B* Sum (求B进制的异或和)

CSU 1155 |a-b|

CSU 1160 十进制-十六进制

CSU 1163 寒衣调

CSU 1205 Rectangles II

CSU 1212 中位数

CSU 1215 稳定排序

CSU 1240 低调,低调。(异或找出2个只出现1次的数)

CSU 1286 Same Integers

CSU 1290 Random Integers

CSU 1344 Special Judge

CSU 1732 XueXX and Binary(二进制中1的个数)

CSU 1753 野心

CSU 1767 想打架吗?算我一个!所有人,都过来!(2)

CSU 1779 NBUT 1641 “错误的算法”

CSU 1785 NBUT 1647 又一道简单题

CSU 1791 ceremony

CSU 1866 Apache and new sports competition

CSU 1867 John and Health rate

CSU 1868 潜在好友

CSU 1869 树上最大值

CSU 1966 Password Hacking(排序不等式)

CSU 1970 LXX数

CSU 2141 新的开始

BZOJ - 1411 硬币游戏

BZOJ - 3517 翻硬币(异或)

Celebration SPOJ - CELEBRATION

HDU - 1128 Self Numbers

HDU - 1172 猜数字

HDU - 1214 圆桌会议

HDU - 1270 小希的数表

HDU - 1717 小数化分数2

HDU - 2006 求奇数的乘积

HDU - 2010 水仙花数(CSU 1261)

HDU - 5272 Dylans loves numbers

HDU - 5583 Kingdom of Black and White

HDU - 5832 A water problem

HDU - 1465 不容易系列之一(错排数)

HDU - 2042 不容易系列之二

HDU - 2045 不容易系列之(3)—— LELE的RPG难题

HDU - 2049 不容易系列之(4)——考新郎

HUST - 1228 区间合并

HYSBZ - 1599 笨重的石子

OpenJ_Bailian - 2733 判断闰年

POJ - 1032 Parliament( 把正整数n表示成若干个不同的正整数的和,求积的最大值)

POJ - 2926 Requirements

POJ 2299 Ultra-QuickSort

POJ 2531 Network Saboteur

SGU139:Help Needed(拼图)

三角形问题 FZU - 1881


CSU 1035 Max DPS

题目:

Description
       Liam 喜欢玩电脑游戏,他的最爱是“World of Bugcraft”。Liam在游戏中扮演了一个法师。法师通过吟唱法术攻击敌人。由于一开始Liam非常弱小,他只会一种法术—“火球术”,每次施展火球术都要消耗他3.5秒的施法时间。每个火球术对敌人造成1000点的基础伤害。有时候,火球术会造成致命一击,这时,火球术便会造成双倍伤害(初始情况下,Liam施放的“火球术”有10%的几率造成致命一击)。

       World of Bugcraft 给玩家提供了一定的“能力点”,玩家可以自由分配能力点来强化三项属性:法术能量、致命几率和施法速度。

       法术能量:每一点“能力点”可以转化为一点法术能量,每一点法术能量都能提高Liam施放的法术所造成的伤害。例如Liam有20点法术能量,那么他的火球术就能造成1000+20=1020点伤害,如果这次火球术产生了致命一击,那么就造成1020*2=2040点伤害。

       致命几率:每20点“能力点”可以转化为1%的致命几率,假设Liam使用了30点“能力点”用于强化致命几率,那么他就有(10+30/20)%=11.5%的致命几率。当然,致命几率的上限为100%。

       施法速度:每15点“能力点”可以转化为1%的施法速度。假设Liam使用了150点“能力点”用于强化施法速度,那么他施放火球术的时间就变成了3.5/(1+(150/15)%)=35/11s。

       在游戏中,玩家们经常以每秒伤害量DPS(Damage Per Second)来衡量角色的强弱。计算DPS的公式如下:

f = B*(1+C)/T

其中B表示单个法术在未产生致命一击时的伤害。C表示致命一击的几率,T表示单个法术的施法时间。

       现在我们可以计算初始情况下Liam的DPS期望值:

f1 = 1000*(1+10%)/3.5 =314.286

       假如Liam有200点“能力点”,并且他将20点转化为法术能量,30点转化为致命几率,150点转化为施法速度,那么他的DPS期望值就变成了

f2=1020*(1+11.5%)/(35/11)=357.437

       可见分配了“能力点”后LIAM的DPS有了很大提高,可是这样的分配方案显然不能最大化Liam的DPS,如果Liam将200点“能力点”全部转化为法术能量,那么他的DPS期望值就变成了

f3=1200*(1+10%)/3.5=377.143

       f3是能力点S=200时所能达到的最大DPS值,可是当S不等于200时呢?你能帮助他找到最优的分配方案,计算出最大化的DPS吗?(假设能力点可以拆分成非整数来分配)

Input
       第一行,一个正整数N,表示测试用例的数目

       第2到N+1行,每行一个正整数S(0 < S ≤ 10000),S表示Liam拥有的能力点数。

Output
       每个测试用例占一行,输出最大可能的DPS,保留小数点后3位有效数字。

Sample Input
2
200
3000
Sample Output
377.143
1610.346

题意:给出s,求非负实数x,y,z满足x+y+z=s且y<=1800
使得(x + 1000)*(y + 2200)*(z + 1500) / 10500000最大,输出这个最大值
代码:
 

#include<iostream>
#include<stdio.h>
using namespace std;
 
int main()
{
	int t, ss;
	cin >> t;
	while (t--)
	{
		scanf("%d", &ss);
		double x = 0, y = 0, z = 0, s = ss;
		if (s <= 500)x += s;
		else
		{
			s -= 500, x += 500;
			if (s <= 1400)x += s / 2, z += s / 2;
			else
			{
				s -= 1400, x += 700, z += 700;
				if (s <= 5400)x += s / 3, y += s / 3, z += s / 3;
				else s -= 5400, x += s / 2 + 1800, y += 1800, z += s / 2 + 1800;
			}
		}
		printf("%.3f\n", (x + 1000)*(y + 2200)*(z + 1500) / 10500000);
	}
	return 0;
}

CSU 1040 Round-number

题目:

Description
    Most of the time when rounding a given number, it is customary to round to some multiple of a power of 10. However, there is no reason why we cannot use another multiple to do our rounding to. For example, you could round to the nearest multiple of 7, or the nearest multiple of 3.
    Given an int n and an int b, round n to the nearest value which is a multiple of b. If n is exactly halfway between two multiples of b, return the larger value.

Input
Each line has two numbers n and b,1<=n<=1000000,2<=b<=500

Output
The answer,a number per line.

Sample Input
5 10
4 10
Sample Output
10
0

代码:
 

#include<iostream>
using namespace std;
 
int main()
{
	int n, b, c;
	while (cin >> n >> b)
	{
		c = n % b;
		cout << n - c + b * (c * 2 >= b) << endl;
	}
	return 0;
}

CSU 1042 遥控机器人

题目:

Description
机器人站在笛卡尔坐标系的原点,面向y轴正方向,给定若干指令,求机器人最终位置。

Input
 多组测试数据,每组数据第一行为m,表示有m个操作,0 < m < 100。

接下来m行,每行一个指令。

指令格式:

“TURN”:右转90度。

“GO” NUM:直走NUM的距离。

Output
 每组数据对应一行输出机器人最终所在的坐标,空格隔开,保留3位小数。

数据保证最终结果可以用double精确表示。
Sample Input
3
TURN
GO 1
TURN
Sample Output
1.000 0.000


代码:
 

#include<iostream>
#include<stdio.h>
#include<string>
using namespace std;
 
int main()
{
	int n, dx[4] = { 0,1,0,-1 }, dy[4] = { 1,0,-1,0 };
	while (cin>>n)
	{
		double x = 0, y = 0, l;
		int k = 0;
		string s;
		while (n--)
		{
			cin >> s;
			if (s[0] == 'T')k = (k + 1) % 4;
			else
			{
				cin >> l;
				x += l * dx[k], y += l * dy[k];
			}
		}
		printf("%.3lf %.3lf\n", x, y);
	}
	return 0;
}

CSU 1114 平方根大搜索

题目:

Description
在二进制中,2的算术平方根,即sqrt(2),是一个无限小数1.0110101000001001111...
给定一个整数n和一个01串S,你的任务是在sqrt(n)的小数部分(即小数点之后的部分)中找到S第一次出现的位置。如果sqrt(n)是整数,小数部分看作是无限多个0组成的序列。
Input
输入第一行为数据组数T (T<=20)。以下每行为一组数据,仅包含一个整数n (2<=n<=1,000,000)和一个长度不超过20的非空01串S。

Output
对于每组数据,输出S的第一次出现中,第一个字符的位置。小数点后的第一个数字的位置为0。输入保证答案不超过100。

Sample Input
2
2 101
1202 110011
Sample Output
2
58

代码:

#include<iostream>
#include<math.h>
#include<string>
#include<string.h>
using namespace std;
 
int main()
{
	int t;
	cin >> t;
	double n;
	char ch1[130], ch2[30];
	while (t--)
	{
		cin >> n >> ch2;
		double s = int(sqrt(n)), a = 1;
		n -= int(s*s);
		for (int i = 0; i < 120; i++)
		{
			a /= 2;
			if ((s*2 + a)*a < n)
			{
				n -= (s * 2 + a)*a;
				s += a;
				ch1[i] = '1';
			}
			else ch1[i] = '0';
		}
		for (int i = 0; i <= 100; i++)
		{
			bool flag = true;
			for (int j = 0; j < strlen(ch2);j++)if (ch1[i + j] != ch2[j])flag = false;
			if (flag)
			{
				cout << i << endl;
				break;
			}
		}
	}
	return 0;
}

CSU 1131 Nim-B* Sum (求B进制的异或和)

题目:

Description
The game of NIM is played with any number of piles of objects with any number of objects in each 
pile.  At each turn, a player takes one or more (up to all) objects from one pile.  In the normal form of 
the game, the player who takes the last object is the winner.  There is a well-known strategy for this 
game based on the nim-2 sum. 
 
The Nim-B sum (nim sum base B) of two non-negative integers X and Y (written NimSum(B, X, Y)) 
is computed as follows: 
 
1)  Write each of X and Y in base B. 
2)  Each digit in base B of the Nim-B sum is the sum modulo B of the corresponding digits in the 
base B representation of X and Y. 
 
For example: 
NimSum(2, 123, 456) = 1111011 ¤   111001000 = 110110011 = 435 
NimSum(3, 123, 456) = 11120 ¤   121220 = 102010 = 300 
NimSum(4, 123, 456) = 1323 ¤   13020 = 10303 = 307 
 
The strategy for normal form Nim is to compute the Nim-2 sum T of the sizes of all piles.  If at any 
time, you end your turn with T = 0, you are guaranteed a WIN.  Any opponent move must leave T not 
0 and there is always a move to get T back to 0.  This is done by computing 
NimSum(2, T, PS)for each pile; if this is less than the pile size (PS), compute the difference 
between the PS and the Nim-2 sum and remove it from that pile as your next move. 
 
Write a program to compute NimSum(B, X, Y).

Input
The first line of input contains a single integer P, (1 £ P £ 1000), which is the number of data sets that 
follow.  Each data set is a single line that contains the data set number, followed by a space, followed 
by three space separated decimal integers,  B, X and Y.  2 <= B <= 2000000, 0 <= X <= 
2000000, 0 <= Y <= 2000000.

Output
For each data set there is one line of output.  It contains the data set number followed by a single 
space, followed by N, the decimal representation of the Nim sum in base B of X and Y.

Sample Input

1 2 123 456
2 3 123 456
3 4 123 456
4 5 123 456
Sample Output
1 435
2 300
3 307
4 429

代码:

#include<iostream>
using namespace std;
 
int main()
{
	int n, p, x, y;
	cin >> n;
	while (cin >> n >> p >> x >> y)
	{
		int sum = 0, a = 1, ans = 0;
		while (x || y)
		{
			ans += (x + y) % p*a;
			a *= p, x /= p, y /= p;
		}
		cout << n << " " << ans << endl;
	}
	return 0;
}

CSU 1155 |a-b|

题目:

Description

  Your task is to Calculate |a-b|.

Input

  There multiple lines of data. Each line consists of a pair of integers a and b(0<=a,b<=2^63), separated by a space, one pair of integers per line.

Output

  For each pair of input integers a and b you should output the result of |a-b| in one line, and with one line of output for each line in input.

Sample Input

1 5
20 10
Sample Output

4
10

用long long 刚好不会越界

是真的完全刚好,结果可能刚好就是long long 的最大值,如果再大1就不能只用long long了

代码:
 

#include<iostream>
using namespace std;
 
int main()
{
    long long m, n;
    while (cin >> m >> n)
    {
        if (m > n)cout << m - n;
        else cout << n - m;
        cout << endl;
    }
    return 0;
}

CSU 1160 十进制-十六进制

题目:

Description

 把十进制整数转换为十六进制,格式为0x开头,10~15由大写字母A~F表示。

Input

 每行一个整数x,0<= x <= 2^31。

Output

 每行输出对应的八位十六进制整数,包括前导0。

Sample Input

0
1023
Sample Output

0x00000000
0x000003FF

代码:
 

#include<iostream>
using namespace std;
 
int main()
{
    int n;
    while (cin >> n)
    {
        char ch[8];
        for (int i = 7; i >= 0; i--)
        {
            int t = n % 16;
            n /= 16;
            if (t < 10)ch[i] = '0' + t;
            else ch[i] = 'A' + t - 10;
        }
        cout << "0x";
        for (int i = 0; i < 8; i++)cout << ch[i];
        cout << endl;
    }
    return 0;
}

CSU 1163 寒衣调

Description
男从戎,女守家。一夜,狼烟四起,男战死沙场。从此一道黄泉,两地离别。最后,女终于在等待中老去逝去。逝去的最后是换尽一生等到的相逢和团圆。
某日两人至奈何桥前,服下孟婆汤。
每滴孟婆汤都有强度不一的药效,设一碗孟婆汤共N滴(0<N<100000),其中第i滴(0≤i<N)用b[i]表示。
孟婆汤的药效与原料有关,设熬制前同样有N滴原料,第i滴原料用a[i]表示,0≤a[i]<2^32。
药效b[i]的计算方法为b[i]=(a[0]*a[1]*...*a[N-1]/a[i])%m(假设0/0=1),0<b[i]<2^32。
Input
每行开头给出原料数量N,取模数m,紧接着的一行按顺序给出原料a[i]。求出熬制所成孟婆汤的药效b[i],每次输完一碗孟婆汤的药效后以换行结尾。
Output
 求出熬制所成孟婆汤的药效b[i],每碗孟婆汤后以换行结尾。

Sample Input
5 11
2 7 5 3 9
3 7
9 8 5
Sample Output
10 6 4 3 1
5 3 2

代码:

#include<iostream>
#include<stdio.h>
using namespace std;
 
long long a[100000], b[100000], c[100000];
 
int main()
{
	int n, m;
	while (cin >> n >> m)
	{
		for (int i = 0; i < n; i++)scanf("%lld", &a[i]);
		b[n] = 1, c[0] = a[0];
		for (int i = n-1; i >= 0; i--)b[i] = b[i + 1] * a[i] % m;
		for (int i = 1; i < n; i++)c[i] = c[i - 1] * a[i] % m;
		if (a[0] == 0)printf("1");
		else printf("%d", b[1]);
		for (int i = 1; i < n; i++)
		{
			if (a[i] == 0)printf(" 1");
			else printf(" %d", c[i - 1] * b[i + 1] % m);
		}
		printf("\n");
	}
	return 0;
}

CSU 1205 Rectangles II

题目:

Description
现在有一个由N行M列共N * M个小正方形组成的矩形,每个小正方形上都标有一个不超过100的正整数。你需要计算出有多少个这样的子矩形,其涵盖的所有小正方形上的整数之和小于或等于S。

Input
        输入数据的第一行包含一个整数T (1 <= T <= 200),表示接下来一共有T组测试数据。

        对于每组测试数据,第一行包含三个整数N (1 <= N <= 100)、M (1 <= M <= 100)、S (1 <= S <= 1000000),含义同上。接下来一共有有N行,每行均有M个不超过100的正整数,分别描述了N行M列个小正方形上标有的整数,其中第i行第j列的整数描述了第i行第j列的小正方形上的整数。

        输入数据中至多有20组测试数据满足N > 20或M > 20。

Output
对于每组测试数据,用一行输出一个整数,表示由多少个这样的子矩形,其涵盖的所有小正方形上的整数之和小于或等于S。

Sample Input
3
1 3 2
1 1 1
2 2 4
1 1
1 1
2 3 7
1 2 3
4 5 6
Sample Output
5
9
11


代码:
 

#include<iostream>
#include<stdio.h>
using namespace std;
 
int main()
{
	int t, n, m, s, num[101][101], summ[101][101];
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d%d", &n, &m, &s);
		for (int j = 0; j <= m; j++)summ[0][j] = 0;
		for (int i = 1; i <= n; i++)
		{
			summ[i][0] = 0;
			for (int j = 1; j <= m; j++)
			{
				scanf("%d", &num[i][j]);
				summ[i][j] = summ[i][j - 1] + summ[i - 1][j] - summ[i - 1][j - 1] + num[i][j];
			}
		}
		int re = 0;
		for (int l = 0; l < m; l++)for (int r = l + 1; r <= m; r++)
		{
			int d = 0;
			for (int u = 0; u < n; u++)
			{
				while (d < n && summ[d + 1][r] - summ[d + 1][l] - summ[u][r] + summ[u][l] <= s)d++;
				re += d - u;
			}
		}
		printf("%d\n", re);
	}
	return 0;
}

CSU 1212 中位数

题目:

Description

长为L的升序序列S,S[L / 2]为其中位数。

给出两个等长升序序列S1和S2,求两序列合并并排序后的中位数。

Input

多组数据,每组第一行为n,表示两个等长升序序列的长度。

接下来n行为升序序列S1的元素,再接下来n行为升序序列S2的元素。

1 <= n <= 10 ^ 5,S内容为整数。

不超过5组数据。

Output

每组数据,输出合并并排序后的序列的中位数。

Sample Input

5
11
13
15
17
19
2
4
6
8
20
Sample Output

11

代码:
 

#include<iostream>
using namespace std;
 
int main()
{
    int n;
    while (cin >> n)
    {
        int *a = new int[n];
        int *b = new int[n];
        for (int i = 0; i < n; i++)cin >> a[i];
        for (int j = 0; j < n; j++)cin >> b[j];
        int x = 0,y=0;
        while (x + y < n-1)
        {
            if (a[x] < b[y])x++;
            else y++;
        }
        if (a[x] < b[y])cout << a[x];
        else cout << b[y];
        cout<<endl;
    }
    return 0;
}

CSU 1215 稳定排序

题目:


Description

给出二元数组a[MAXN][2],按第一个关键值从小到大排序后输出,要求第一关键值相同情况下不改变原数组次序

Input

每组数据第一行为整数n,1 <= n <= 10 ^ 5。

接下来n行每行两个整数空格隔开。

Output

输出排序后的数组

Sample Input

3
2 4
1 0
2 3
3
4 2
0 4
0 2
Sample Output

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

这个题目需要稳定的排序,而且n还比较大,必须是归并排序这种可以在O(n log n)时间内排序的算法。

代码:
 

#include<iostream>
#include<stdio.h>
using namespace std;

struct node
{
	int key;
	int b;
};

node list[100001];
node list1[100001];

void merge(node *s, node *t, int i, int m, int n)
{
	int k = i;
	int j = m + 1;
	for (; i <= m && j <= n; ++k)
	{
		if (s[i].key <= s[j].key)t[k] = s[i++];
		else t[k] = s[j++];
	}
	if (i <= m)for (int ii = k, jj = i; ii <= n; ii++, jj++)t[ii] = s[jj];
	if (j <= n)for (int ii = k, jj = j; ii <= n; ii++, jj++)t[ii] = s[jj];
}

void msort(node *sr, node *tr1, int s, int t, int n)
{
	if (s == t)tr1[s] = sr[s];
	else
	{
		node *list = new node[n];
		int m = (s + t) / 2;
		msort(sr, list, s, m, n);
		msort(sr, list, m + 1, t, n);
		merge(list, tr1, s, m, t);
		delete list;
	}
}

int main()
{
	int n;
	while (cin >> n)
	{
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &list[i].key);
			scanf("%d", &list[i].b);
		}
		msort(list, list1, 0, n - 1, n);
		for (int i = 0; i<n; i++)printf("%d %d\n", list1[i].key, list1[i].b);
	}
	return 0;
}

这个题目也可以用sort,但是sort是不稳定排序,要想实现稳定排序需要扩充数据。

下面3个///标记的地方就是我对汤学弟的代码进行修改的3个地方,扩充了结构体才能变成稳定排序

#include<iostream>
#include<algorithm>
using namespace std;
struct num{
	long data1;
	long data2;
	long key;//
}Num[100005];
bool cmp(num a, num b)
{
	if (a.data1 == b.data1)
		return a.key < b.key;//
	else
		return a.data1<b.data1;
}
int main()
{
	ios::sync_with_stdio(false);
	int n;
	while (cin >> n)
	{
		for (int i = 0; i < n; i++)
			cin >> Num[i].data1 >> Num[i].data2, Num[i].key = i;///
		sort(Num, Num + n, cmp);
		for (int i = 0; i<n; i++)
			cout << Num[i].data1 << " " << Num[i].data2 << endl;
	}
	return 0;
}

CSU 1240 低调,低调。(异或找出2个只出现1次的数)

Description
Staginner总是喜欢把自已的名字写在他出的题目里。CSU-ACM协会的会长想,这孩子是不是想出名想疯了,于是决定考一考他。

任意正整数N,不大于N且与N互质的正整数个数记为P,现在给一列与N互质的正整数,只知道一些数各出现P次,而有两个数各只出现了1次,求这两个数。

会长对Staginner说,你要是解出了这个题,这道题也加上你的名字。

Staginner要求道,很多数啊,那你得跟我说两遍。

打赌的结果大家已经看到了,那么你能不能解决这个问题呢?

Input
多组数据, 每组数据两行,第一行为两个正整数N、K,2 < N < 211,1 < K < 218

第二行K个正整数X,1 < X < 230,第三行重复这K个数

Output
输出只出现一次的两个数,小的在前,一个空格隔开。

Sample Input
8 6
5 5 5 5 3 7
5 5 3 5 5 7
7 14
1 1 1 1 1 1 9 6 3 3 3 3 3 3
1 1 9 1 1 1 1 6 3 3 3 3 3 3
Sample Output
3 7
6 9

代码:
 

#include<iostream>
using namespace std;
 
int main()
{
	int n, k, s, s1, s2;
	while (cin >> n >> k)
	{
		s = 0;
		for (int i = 0; i < k; i++)
		{
			cin >> n;
			s ^= n;
		}
		s = s & -s;
		s1 = 0, s2 = 0;
		for (int i = 0; i < k; i++)
		{
			cin >> n;
			if (s&n)s1 ^= n;
			else s2 ^= n;
		}
		if (s1 > s2)s1 ^= s2 ^= s1 ^= s2;
		cout << s1 << " " << s2 << endl;
	}
	return 0;
}

CSU 1286 Same Integers

题目:

Description
We have N integers, you can cost 1 unit cost to increase or decrease any integer by 1. If you can cost K units cost at most, what is the maximum number of same integers we can get?

Input
There is an integer T (1 <= T <= 200) in the first line, means there are T test cases in total. For each test case, the first line has two integers N (1 <= N <= 10^5), K (1 <= K <= 10^9), which has the same meaning as above. Then next line has N integers in range [1, 10^9], indicate all the integers we have. There are at most 10 test cases that satisfy N > 100.

Output
For each test case, you should print one integer in a line, indicates the maximum number of same integers we can get.

Sample Input
3
3 1
1 4 2
3 2
1 4 2
3 3
1 4 2
Sample Output
2
2
3

代码:
 

#include<iostream>
#include<algorithm>
using namespace std;
 
int num[100005];
 
int main()
{
	int t, n, k;
	cin >> t;	
	while (t--)
	{
		cin >> n >> k;
		for (int i = 0; i < n; i++)scanf("%d", &num[i]);
		sort(num, num + n);
		int ans = 0, l = 0, r = 0, sk = 0;
		while (r < n - 1)
		{
			while (sk <= k && r < n - 1)r++, sk += num[r] - num[(l + r) / 2];
			if (sk>k)sk -= num[r] - num[(l + r) / 2], r--;
			if (ans < r - l + 1)ans = r - l + 1;
			sk -= num[(l + r + 1) / 2] - num[l++];
		}
		printf("%d\n", ans);
	}
	return 0;
}

CSU 1290 Random Integers

题目:

Description
We choose an integer K (K > 0). Then we generate N (N > 0) integers one by one randomly, each of them is in range [0, K - 1], and the appearing probabilities of each interger is the same,they are all 1/K.
Can you tell us the expectation of the number of distinct integers in that N integers?

Input
There is an integer T (1 <= T <= 200) in the first line, means there are T test cases in total.
For each test case, there are two integers K (1 <= K <= 1000), N (1 <= N <= 1000), which have the same meaning as above.

Output
For each test case, you should print the result in one line. You should keep the first 5 digits after the decimal point.

Sample Input
5
1 1
2 2
3 2
3 4
5 3
Sample Output
1.00000
1.50000
1.66667
2.40741
2.44000

代码:

#include<iostream>
using namespace std;
 
int main()
{
	int t, n, k;
	cin >> t;	
	while (t--)
	{
		cin >> k >> n;
		double a = k, b = (a - 1) / a;
		a = 1;
		while (n--)a *= b;
		printf("%.5f\n", (1 - a)*k);
	}
	return 0;
}

CSU 1344 Special Judge

题目:

Description

Given a positive integer n, find two non-negative integers a, b such that a2 + b2 = n.

Input

The first line contains the number of test cases T (1 <= T <= 1000).
For each test case, there is only one line with an integer n (1 <= n <= 109) as defined above.

Output

For each test case, output two integers a, b separated by a single space such that a2 + b2 = n. If there are multiple solutions, anyone will be accepted. If there is no solution, output “-1” (without quotation marks) instead.

Sample Input

4
2
3
4
4
Sample Output

1 1
-1
0 2
2 0
Hint

还记得我们在“A Sample Problem”中说到的OJ的判题形式吗?这个题主要让我们来熟悉一下OJ的另一种名为Special Judge的判题形式。所谓的Special Judge是指OJ将使用一个特定的程序来判断我们提交的程序的输出是不是正确的,而不是单纯地看我们提交的程序的输出是否和标准输出一模一样。

一般使用Special Judge都是因为题目的答案不唯一,更具体一点说的话一般是两种情况:

(1)题目最终要求我们输出一个解决方案,而且这个解决方案可能不唯一。比如这个题目就是这样的,只要求我们输出一组a、b满足a^2 + b^2 = n,而对于不同的n,可能有多组a、b满足这一条件,像n=4时,就有a=2、b=0和a=0、b=2这两组解,这时我们输出任意一组解都可以。

(2)题目最终要求我们输出一个浮点数,而且会告诉我们只要我们的答案和标准答案相差不超过某个较小的数就可以,比如0.000001。这种情况我们只要保证我们的中间运算过程尽可能精确就可以了,并且最后输出答案的时候保留的小数位数足够多就行了,比如如果要求我们的答案和标准答案相差不超过0.01,那么一般我们保留3位小数、4位小数等等都是可以的,而且多保留几位小数也没什么坏处。

为了能让大家更清楚的了解Special Judge的原理,这里我把这个题目的执行Special Judge功能的程序的源代码贴出来了。

大家也许发现了,这个执行Special Judge功能的程序并不那么完美,比如我们在输出a和b的时候中间如过用两个空格分隔a和b的话也是可以通过这个题目的,但是这样实际上是不符合题目在Output中约定的输出格式的。我在这里之所以用了这样一个不是很完美的Special Judge,主要原因是写一个十分完美的Special Judge是要花费很大“力气”的,而且有些时候输出的格式并不不是这个题目的核心,更重要的应该是我们输出的a和b应当是符合要求的。不过大家千万不能凡是遇到Special Judge的题目就不管输出格式了,因为并不是所有写Special Judge程序的人都会像我这样偷工减料,我们最好还是要严格按照题目的要求来输出答案。

接下来我们分析一下这个题目应当怎么解决。

最容易想到的办法就是枚举所有可能的a、b,看是否存在一组a、b满足a^2 + b^2 = n。那么所有的可能的a、b有多少呢?最起码的一个限制条件就是a<=n且b<=n,不过我们还能让限制条件更“精确”一些,就是a<=sqrt(n)且b<=sqrt(n),虽然这样枚举量减少了不少,但是我们枚举所有可能的a、b的话还是要枚举sqrt(n)*sqrt(n) = n次,由于n最大可能是10^9,这样的枚举量还是不能承受。

但其实我们是没有必要枚举b的,因为当a确定时b=sqrt(n - a^2),我们可以将b直接求出来,如果b是整数的话,我们就算找到了一组解。这样如果我们枚举完所有可能的a后还没找到一组解的话,就可以说明是无解了。

如果觉得代码写起来会有困难的话,可以参考一下我在下面给出的示例代码,不过最后一定要按自己的思路写一个完整的代码(编写自己的代码时就不要再参考示例代码了,要一气呵成~)并获得“Accept”哟!O(∩_∩)O~

这个程序在计算b时实际上是在计算满足b^2 <= n - a^2的最大的b,之后再判断是否满足a^2 + b^2 = n就可以了。计算b的代码是b=(int)sqrt(n - a^2 + 0.5),之所以+0.5,一个原因是因为这样不会改变计算结果(也就是说这样求出来的仍是满足b^2 <= n - a^2的最大的b),另一个原因是怕出现浮点数误差(也就是说假如真的存在整数b满足a^2 + b^2 = n,通过(int)sqrt(n - a^2)未必能计算出正确的b,因为毕竟sqrt()这个函数是浮点数运算,万一算出的b丢失了一些精度那么向下取整之后就会变成b-1了)。

代码:

#include <iostream>
#include<math.h>
using namespace std;
 
int main()
{
	int t, n;
	cin >> t;
	while (t--)
	{
		cin >> n;
		int i = 0, j = -1;
		bool b = true;
		for (; i*i <= n; i++)
		{
			j = (int)(sqrt(n - i*i+0.1));
			if (j*j == n - i*i)
			{
				b = false;
				break;
			}
		}
		if (!b)cout << i << " " << j;
		else cout << -1;
		cout << endl;
	}
	return 0;
}

CSU 1732 XueXX and Binary(二进制中1的个数)

题目:

Description
XueXX is a clever boy. And he always likes numbers in binary(二进制). What an interesting hobby!
Now XueXX has some number in decimal(十进制), he wants to know how many “1”s in a number if the number is written in binary.
Input
The first line of input contains the number of test cases T (T<=100). The descriptions of the test cases follow: The first line of each test case contains one integer a (0<a<=1,000,000,000), standing for the number in decimal.

Output
For each test case, output a single line containing the result.
Sample Input
3
1
91
735
Sample Output
1
5
8

代码:
 

#include<iostream>
#include<stdio.h>
using namespace std;
 
int main()
{
	int t, a, b;
	cin >> t;
	while (t--)
	{
		cin >> a;
		b = 0;
		while (a)b += a % 2, a /= 2;
		cout << b << endl;
	}
	return 0;
}

CSU 1753 野心

题目:

Description

C国要用一个表面积为S的圆锥将核燃料包起来。

C国希望包住的核燃料体积尽量大,J总统想知道体积最大可以是多少。
注意圆锥的表面积包括底面和侧面。
Input

一行一个整数,表示表面积S。(1 <= S <= 10^9)
Output

一行一个实数,表示体积。
Sample Input

8
Sample Output

1.504505556127

代码:
 

#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
 
int main()
{
    int t;
    cin >> t;
    cout << setprecision(13)<< sqrt(2 * t / 3.14159265358979323)*t / 12; 
    return 0;
}

CSU 1767 想打架吗?算我一个!所有人,都过来!(2)

题目:

Description
现在《炉石传说》这款卡牌游戏已经风靡全球。2015年加入环境的“黑石山的火焰”扩展带来了一个新套牌的核心卡片“恐怖的奴隶主”,而这套统治游戏的套牌叫做“奴隶战”。“恐怖的奴隶主”的登场音效“想打架吗?算我一个!”一定在所有这个时代的《炉石传说》玩家心里留下来难以磨灭的印象。
“恐怖的奴隶主”是一个有3点生命值的生物,当其在场上受到非致命伤害时(如3点生命值的奴隶主受到1点或2点伤害时,或者2点生命值的奴隶主受到1点伤害时)会召唤一个新的3点生命值的“恐怖的奴隶主”,受到致命伤害(伤害大于等于现有生命值)时则会直接死去。另外一类卡片可以使全部生物造成1点伤害(降低1点生命),被称为“旋风斩效果”。因此“恐怖的奴隶主”,在场上经过多次“旋风斩效果”就可能由一个变成很多个,同时发出那个令人恐惧的声音“所有人,都过来!”。
另一方面,《炉石传说》规定,场上最多存在7个生物,这极大地限制了“恐怖的奴隶主”“越生越多”。当一次“旋风斩效果”发生时,优先处理受到非致命伤害的“恐怖的奴隶主”,召唤新的“恐怖的奴隶主”,直到生物数量达到7个不再继续召唤新的“恐怖的奴隶主”,然后清除掉生命值降为0或0以下的“恐怖奴隶主”。如场上有7个生命值为1的“恐怖的奴隶主”,则一次“旋风斩效果”后场上有0个“恐怖的奴隶主”。又如,场上有6个生命值为3的“恐怖的奴隶主”,则一次“旋风斩效果”后场上有6个2点生命的“恐怖的奴隶主”以及1个3点生命的“恐怖的奴隶主”。又如,场上有4个1点生命的“恐怖的奴隶主”以及2个2点生命的“恐怖的奴隶主”,则一次“旋风斩效果”后场上有2个1点生命的“恐怖的奴隶主”以及1个3点生命的“恐怖的奴隶主”。
在本系列题目1中我们已经知道了如何计算1个“恐怖的奴隶主”在经历n次旋风斩效果后会剩下多少。现在问题变得更复杂了,经过一场战斗和玩家的一通操作,场上剩下了一些1点生命,一些2点生命,一些3点生命的奴隶主,现在问这些奴隶主经过n次旋风斩效果,场面会变成什么样子。

Input
有多组数据。
每组数据一行,hp1,hp2,hp3,n(hp1+hp2+hp3<=7,0<=n<=10^6)
分别代表1点生命,2点生命,3点生命的奴隶主个数,以及之后旋风斩次数。

Output
每组用一行输出最终1点生命,2点生命,3点生命的奴隶主个数,格式见样例。

Sample Input
0 0 1 3
1 1 2 2
Sample Output
1 2 3
2 3 1
 

我一般都是写while(cin>>a>>b)这样的,从来不写EOF

今天才知道while (scanf("%d %d %d %d", &h1, &h2, &h3, &n) )是无法读取变量的,必须要有!= EOF

这个题目的关键就是找到一个比n小的数x,使得如果前面3个数不变,n改成x,结果是一样的。

因为n可以大到10^6,我找到的x是不超过120的,应该来说这个步骤是很有必要的。

所以,为什么是120呢?

因为h1+h2+h3<=7,这个不等式有120个非负解,所以从任何一个状态开始,最多120步,一定会踏入某个循环。

代码中的120-sum就是我求出来的周期。

注意,这个循环圈不一定包括初始状态!

所以x一定要以sum为基础,不能以0为基础。

代码:

#include<stdio.h>
 
int main()
{
    int h1,h2,h3,n;
    int t, sum;
    int n1, n2, n3;
    int m1, m2, m3;
    while (scanf("%d %d %d %d", &h1, &h2, &h3, &n) != EOF)
    {
        if (n > 120)
        {
            n1 = h1;
            n2 = h2;
            n3 = h3;
            for (int i = 0; i<120; i++)      //找出120次之后的状态n1,n2,n3
            {
                t = n2 + n3;
                if (t > 7 - n1 - t)t = 7 - n1 - t;
                n1 = n2;
                n2 = n3;
                n3 = t;
            }
            m1 = h1;
            m2 = h2;
            m3 = h3;
            sum = 0;
            while (1)
            {
                t = m2 + m3;
                if (t > 7 - m1 - t)t = 7 - m1 - t;
                m1 = m2;
                m2 = m3;
                m3 = t;
                sum++;
                if (n1 == m1&&n2 == m2&&n3 == m3)break;
            }
            n = sum + (n - 120) % (120 - sum);
        }
        n1 = h1;
        n2 = h2;
        n3 = h3;
        while (n--)
        {
            t = n2 + n3;
            if (t > 7 - n1 - t)t = 7 - n1 - t;
            n1 = n2;
            n2 = n3;
            n3 = t;
        }
        printf("%d %d %d\n", n1, n2, n3);
    }
    return 0;
}

CSU 1779 NBUT 1641 “错误的算法”

题目:


Description

有道题目是这样的:

输入一个n行m列网格,找一个格子,使得它所在的行和列中所有格子的数之和最大。如果答案不唯一,输出任意解即可。比如,在下面的例子中,最优解是(1,3),即第一行和的三列的交点(行从上到下编号为1~n,列从左到右编号为1~m),所有7个数之和为35。

快要比赛的时候,有一个裁判想到了这样一个算法:

首先找一行 r(1<=r<=n) 使得该行所有数之和最大,然后找一列 c(1<=c<=m)使得该列所有数之和最大,最后直接输出(r,c)。如果有多个满足条件的 r,输出最小的 r。对 于 c 同样处理。

显然,这个算法是错的,但它竟然通过了大部分测试数据!你能找出那些让这个错误算法得到 正确结果的“弱”数据,以便裁判们改进这些数据吗?

Input

输入包含不超过 100 组数据。每组数据第一行为两个整数 n, m (1<=n<=500, 1<=m<=500),即行 数和列数。以下 n 行每行包含 m 个 1~100 的整数。输入的总大小不超过 2MB。
Output

对于每组数据,如果错误算法能得到正确结果,输出"Weak",否则输出"Strong"。
Sample Input

4 4
5 5 5 5
1 1 5 1
1 1 5 1
1 1 5 1
5 4
2 5 1 1
1 1 9 1
1 1 1 1
1 1 1 1
1 1 1 1 
Sample Output

Case 1: Weak
Case 2: Strong

这个题目,如果思路清晰的话,一开始就能想明白,只需要计算这个矩阵的行和以及列和就可以算出答案,

也就是说,只需要1个2维数组和2个1维数组即可。

然而我是边写代码边发现这个的,就把一些不必要的数组删掉了。

首先输入list,同时统计row和line。

然后计算“错误的算法”算出来的最大值maxx是多少。

然后直接枚举来判断maxx是不是最优解。

代码:
 

#include<iostream>
#include<string>
#include<string.h>
using namespace std;
 
int n, m, maxx;
int list[500][500];
int row[500], line[500];
 
bool ok()
{
	for (int i = 0; i < n; i++)for (int j = 0; j < m; j++)
		if (row[i] + line[j] - list[i][j] > maxx)return false;
	return true;
}
 
int main()
{
	int cas = 1;
	int keyr, keyl, maxr, maxl;
	while (cin >> n >> m)
	{
		memset(line, 0, sizeof(line));
		memset(row, 0, sizeof(row));
		for (int i = 0; i < n; i++)for (int j = 0; j < m; j++)
		{
			cin >> list[i][j];
			row[i] += list[i][j];
			line[j] += list[i][j];
		}
		keyr = n - 1, keyl = m - 1, maxr = row[n - 1], maxl = line[m - 1];
		for (int i = n - 2; i >= 0; i--)if (maxr <= row[i])
		{
			maxr = row[i];
			keyr = i;
		}
		for (int i = m - 2; i >= 0; i--)if (maxl <= line[i])
		{
			maxl = line[i];
			keyl = i;
		}
		maxx = row[keyr] + line[keyl] - list[keyr][keyl];		
		cout << "Case " << cas++ << ": ";
		if (ok())cout << "Weak";
		else cout << "Strong";
		cout << endl;
	}
	return 0;
}

CSU 1785 NBUT 1647 又一道简单题

题目:

Description

输入一个四个数字组成的整数 n,你的任务是数一数有多少种方法,恰好修改一个数字,把它 变成一个完全平方数(不能把首位修改成0)。比如 n=7844,有两种方法:3844=62^2和 7744=88^2。

Input

输入第一行为整数 T (1<=T<=1000),即测试数据的组数,以后每行包含一个整数 n (1000<=n<=9999)。
Output

对于每组数据,输出恰好修改一个数字,把 n 变成完全平方数的方案数。
Sample Input

2
7844
9121
Sample Output

Case 1: 2
Case 2: 0

因为范围比较小,所以直接枚举就可以判断是不是完全平方数。

而且这样的话,可以忽略掉首位不能变成0这个限制了,代码就变得更有对称美。

代码:
 

#include<iostream>
using namespace std;
 
bool ok(int n)
{
	for (int i = 32; i<100; i++)if (i*i == n)return true;
	return false;
}
 
int f(int n)
{
	int a, b, c, d;
	a = n / 1000;
	b = n / 100 % 10;
	c = n / 10 % 10;
	d = n % 10;
	int sum = 0;
	for (int i = 0; i <= 9; i++)if (ok(n + (i - a) * 1000))sum++;
	for (int i = 0; i <= 9; i++)if (ok(n + (i - b) * 100))sum++;
	for (int i = 0; i <= 9; i++)if (ok(n + (i - c) * 10))sum++;
	for (int i = 0; i <= 9; i++)if (ok(n + i - d))sum++;
	if (ok(n))sum -= 4;
	return sum;
	
}
int main()
{
	int t, n;
	cin >> t;
	for (int cas = 1; cas <= t; cas++)
	{
		cin >> n;
		cout << "Case " << cas << ": " << f(n) << endl;
	}
	return 0;
}

CSU 1791 ceremony

题目:

Sample Input

6
2 1 8 8 2 3
Sample Output

5

这个题目我开始还以为是树状数组。。。仔细一想普通的数组线性的时间就能解决。

如果有k次全部减1的操作

设不超过k的数有sum个,那么还有m-sum个数,需要一次次的进行全消操作。

有一个地方需要注意的是,比如输入2 3 3,那么应该用2次全消操作而不是3次减1操作。

所以minn的初始化需要注意,要设为m

代码:
 

#include<iostream>
using namespace std;

const int n = 1000001;
int c[n];

int main()
{
	int m, x;
	scanf("%d", &m);
	for (int i = 1; i < n; i++)c[i] = 0;
	for (int i = 0; i < m; i++)
	{
		scanf("%d", &x);
		c[x]++;
	}
	int minn =m, sum = 0;
	for (int i = 1; i < n; i++)
	{
		sum += c[i];
		if (minn>m - sum + i)minn = m - sum + i;
	}
	printf("%d\n", minn);
	return 0;
}

CSU 1866 Apache and new sports competition

题目:

Description
Apache is a cheerleader in the new sports competition named "Pashmaks". This competition consists of two part: swimming and then running. People will immediately start running R meters after they finished swimming exactly S meters. A winner is a such person that nobody else finishes running before him/her (there may be more than one winner). Before the match starts, Tavas knows that there are n competitors registered for the match. Also, he knows that i-th person's swimming speed is si meters per second and his/her running speed is ri meters per second. Unfortunately, he doesn't know the values of R and S, but he knows that they are real numbers greater than 0. As a cheerleader, Apache wants to know who to cheer up. So, he wants to know all people that might win. We consider a competitor might win if and only if there are some values of R and S such that with these values, (s)he will be a winner. Apache isn't really familiar with programming, so he asked you to help him.

Input
The first line of input contains a single integer n (1 ≤ n ≤ 2 × 100000). The next n lines contain the details of competitors. i-th line contains two integers si and ri (1 ≤ si, ri ≤ 10000).

Output
In the first and the only line of output, print a sequence of numbers of possible winners in increasing order.

Sample Input
3
1 3
2 2
3 1

3
1 2
1 1
2 1
Sample Output
1 2 3
1 3
我的错误代码:

#include<iostream>
using namespace std;
 
int s[200001], r[200001], m[10001];
 
int main()
{
	int n, M = 0, k = 0;
	cin >> n;
	for (int i = 0; i <= n; i++)m[i] = 0;
	for (int i = 1; i <= n; i++)
	{
		scanf("%d%d", &s[i], &r[i]);
		if (m[s[i]] < r[i])m[s[i]] = r[i];
	}
	for (int i = 10000; i>0; i--)
	{
		if (M >= m[i])m[i] = 0;
		if (M < m[i])M = m[i];
	}
	for (int i = 1; i <= n; i++)if (m[s[i]] == r[i])
	{
		if (k++)cout << " ";
		cout << i;
	}
	return 0;
}

实际上这个思路行不通的。

不光要对于每个s选择最大的r,还要把所有点放在坐标系中,根据斜率来判断,即只有从某个方向凸出来的才行。

标程:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <set>
#include <map>
using namespace std;
#define N 10000
#define ll long long
#define eps 1e-9
int run[N * 20 + 10]; //游泳速度为i的人中跑步速度最快达到run[i]
 
struct Ath{
	int s, r;
	Ath(int s = 0, int r = 0) :s(s), r(r){}
}ath[N * 20 + 10];
int k, s[N * 20 + 10], r[N * 20 + 10];
 
bool can_win(int s1, int r1, int s2, int r2, int s3, int r3)
{
	//s1<s2<s3 , r1>r2>r3 , 判断s2,r2在包夹下能否有机会夺冠
	double t1 = (1.0 / r2 - 1.0 / r1) / (1.0 / s1 - 1.0 / s2);
 
	double t2 = (1.0 / r3 - 1.0 / r2) / (1.0 / s2 - 1.0 / s3);
	//  cout<<t1<<" "<<t2<<endl;
	if (t2 - t1 >= -eps) return true;
	else return false;
}
 
int main()
{
	//  freopen("a.in" , "r" , stdin);
	int n;
	while (~scanf("%d", &n))
	{
		memset(run, 0, sizeof(run));
 
		for (int i = 1; i <= n; i++){
			scanf("%d%d", &s[i], &r[i]);
			run[s[i]] = max(run[s[i]], r[i]);
		}
		k = 0;
		int i;
		for (i = N; i >= 0; i--){
			if (run[i]){
				ath[k++] = Ath(i, run[i]);
				break;
			}
		}
		for (i = i - 1; i >= 0; i--){
			run[i] = max(run[i], run[i + 1]);
			if (run[i] > run[i + 1]){
				while (k>1){
					if (!can_win(i, run[i], ath[k - 1].s, ath[k - 1].r, ath[k - 2].s, ath[k - 2].r)){
						k--;
					}
					else
						break;
				}
				ath[k++] = Ath(i, run[i]);
			}
		}
		map<int, int> m;
		for (int i = 0; i<k; i++){
			m[ath[i].s] = ath[i].r;
		}
		bool flag = true;
		for (int i = 1; i <= n; i++){
			if (m[s[i]] == r[i]){
				if (flag) printf("%d", i);
				else printf(" %d", i);
				flag = false;
			}
		}
		puts("");
	}
	return 0;
}

CSU 1867 John and Health rate

题目:

Description
The cold and flu season is here.John is worried about his cow. In order to monitor the situation of his cow,he do some inspecting everyday,and record the “health rate” for each cow.The “health rate” is a integer which can show the cow’s health condition.The higher a cow’s health rate is ,the healthier the cow is.What’s more,the doctor told John that the k-th small health rate is dangerous.Because the doctor thought there are at most k healthy cows. So John has to find out which number is the k-th small.Can you help him?

Input
Input contains multiple test cases.
The first line contains two integers n,k (1 ≤ n ≤ 1000000,1<=k<=n) — the number of cows and dangerous number. The second line contains n integers,and the i-th integer ai(-10000<=ai<=10000) is the i-th cow’s health rate

Output
Output a single line with the k-th small health rate.

Sample Input
2 1
3 2
5 2
-1 0 -2 5 3
Sample Output
2
-1
就是输入n,k,然后输入n个数,要求输出从小到大第k个数。

线性时间选择的算法是比较复杂的,这里不需要,因为给出了每个数的范围,所以只需要20001个桶即可。

代码:

#include<iostream>
using namespace std;
 
int num[20001];
 
int main()
{
	int n, k, h, key;
	while (cin >> n >> k)
	{
		for (int i = 0; i <= 20000; i++)num[i] = 0;
		for (int i = 0; i < n; i++)
		{
			scanf("%d", &h);
			num[h + 10000]++;
		}
		key = 0;
		while (k>num[key])k -= num[key++];
		cout << key - 10000 << endl;
	}
	return 0;
}

CSU 1868 潜在好友

题目:

Description
小X在搬砖写一个论坛,这个时候老板突然想到一个功能,让小X今天赶快实现。大概就是如果某个人是你好友的好友那么他的头像上面会有特殊的标志。小X想不到较好的办法来解决如何验证两个人是不是好友的好友,现在向你求助。

Input
第一行是一个整数T(1<=T<=100),代表数据组数。 每组数据第一行是两个整数n,m(1<=n,m<=10000),代表这两个人的好友的数量。 之后n行是第一个人的好友id 再之后m行是第二个人的好友id (1<=id<=1e9)

Output
如果第二个人是第一个人的好友的好友输出Yes否则No

Sample Input
2
1 1
1
2
2 3
1
2
2
3
4
Sample Output
No
Yes

代码:
 

#include<iostream>
#include<algorithm>
using namespace std;
 
int f1[10000], f2[10000];
 
int main()
{
	int n, m, kn, km;
	cin >> n;
	while (cin >> n >> m)
	{
		for (int i = 0; i < n; i++)cin >> f1[i];
		for (int i = 0; i < m; i++)cin >> f2[i];
		sort(f1, f1 + n);
		sort(f2, f2 + m);
		kn = 0, km = 0;
		while (f1[kn] != f2[km] && kn < n && km < m)if (f1[kn] < f2[km])kn++; else km++;
		if (kn == n || km == m)cout << "No\n"; else cout << "Yes\n";
	}	
	return 0;
}

CSU 1869 树上最大值

题目:

Description
现在给你一棵根节点编号为1的树,每个节点上都有对应的权值, 求出树上每一层的最大值。(根节点所在位置视为第一层,由此可推,根节点的儿子是处于第二层,etc)

Input
多组数据读入 第一行输入一个正整数n表示树上有n个节点(n<=100000),下一行输入n个正整数v1,v2....vn表示n个节点上对应的权值(vi<=100000), 再下一行输入n-1个正整数(第i个数字v表示,节点i+1的父亲是v,保证v<i+1)

Output
从树自顶向下输出每一层的最大值是多少,每个值之间用空格隔开,全部输出后末尾换行。

Sample Input
6
10 6 8 7 3 2
1 2 1 4 4
Sample Output
10 7 8

代码:

#include<iostream>
using namespace std;
 
int deep[100001], x[100001],m[100001];
 
int main()
{
	int n, p;
	while (cin >> n)
	{
		for (int i = 1; i <= n; i++)scanf("%d", &x[i]);
		deep[1] = 1;
		for (int i = 2; i <= n; i++)
		{
			cin >> p;
			deep[i] = deep[p] + 1;
		}
		for (int i = 1; i <= n; i++)m[i] = 0;
		for (int i = 1; i <= n; i++)if (m[deep[i]] < x[i])m[deep[i]] = x[i];
		for (int i = 1; i <= n; i++)
		{
			if (m[i] == 0)break;
			cout << m[i] << " ";
		}
		cout << endl;
	}
	return 0;
}

CSU 1966 Password Hacking(排序不等式)

题目:

Description
We all know that passwords are not very secure unless users are disciplined enough to use passwords that are difficult to guess. But most users are not so careful, and happily use passwords such as “123456”. In fact, there are lists of commonly used passwords that hackers can use for breaking into systems, and these passwords often work.

You have done a lot of hacking using such lists, and you have a good idea of how likely each password in the list is the correct one (you are very surprised by the number of people using “123456” as their passwords). You have a new account to hack, and you have decided to try each of the passwords in the list one at a time, until the correct one is found. You are absolutely sure that the account you want to hack uses a password in the given list.

What is the expected number of attempts to find the correct passwords, assuming that you try these passwords in the optimal order?

Input
The first line of input contains a positive integer N, the number of passwords in the list. Each of the next N lines gives the password, followed by a space, followed by the probability that the password is the correct one. Each password is a non-empty string consisting only of alphanumeric characters and is up to 12 characters long. Each probability is a real number with 4 decimal places. You may assume that there are at most 500 passwords in the list, and that the sum of all probabilities equals 1. No two passwords in the list are the same.

Output
Output on a single line the expected number of attempts to find the correct passwords using the optimal order. Answers within 10−4 of the correct answer will be accepted.

Sample Input
2
123456 0.6666
qwerty 0.3334

3
qwerty 0.5432
123456 0.3334
password 0.1234
Sample Output
1.3334
1.5802

代码:

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
 
int main()
{
	int n;
	string s;
	double a[501];
	while (cin >> n)
	{
		for (int i = 1; i <= n; i++)cin >> s >> a[i];
		sort(a + 1, a + 1 + n);
		double r = 0;
		for (int i = 1; i <= n; i++)r += a[i] * (n + 1 - i);
		printf("%.4f\n", r);
	}
	return 0;
}

CSU 1970 LXX数

题目:

Description
又是一年集训时,刚出家里赶来的LXX很是郁闷。因为CS市的天气实在是难以忍受了,加之搬寝室到CS大学“老”校区。一天晚上CS大学“老”校区的寝室又停电了,LXX和室友实在是难以呆下去了。于是商量一起去网吧吹空调,但是谁请客是个问题。LXX的室友小Z便甩出一个问题给LXX,只要LXX在1S内计算出来便请客。问题如下:
我有n个数,a[1]~a[n],初始值均为0,现在我要执行n次操作(操作1到操作n),操作i为:把所有的a[t]反转(t%i==0,反转即0->1,1->0)。如果最后的a[i]为1,则称i为LXX数。求最后又多少个LXX数。奈何LXX太弱了,为了能够免费去网吧吹空调,他决定寻求你的帮助。

Input
大量多组数据。每行一个正整数N(N<=1e18)

Output
每行输出一个正整数,即答案LXX的数量。

Sample Input
2
15
Sample Output
1
3


思路:

只有完全平方数被改变的次数是奇数次,其他都是被改变偶数次,也就是没改变。

代码:
 

#include<iostream>
#include<math.h>
using namespace std;
 
int main()
{
	long long n;
	while (~scanf("%lld", &n))printf("%d\n", int(sqrt(n)));
	return 0;
}

CSU 2141 新的开始

题目:

Description
Wells决定定一个小目标——建立一座新的acm实验大楼。他发现CSU新校区有一块长宽为a,b的矩形土地。


Wells给新的acm实验大楼规划了很多的部门和区域,但是Wells有很大的强迫症,所以他每次会在矩阵的土地中截取一个长宽平行于矩形边长的正方形,直到把矩形土地分割光。

同样,Wells想让自己截取的正方形边长总和最小。但是苦逼的Wells还有很多期末考试要预习,这个任务就交给你了。

Input
一行两个正整数a,b.如题目所示,注意a可能小于b。(0<a,b<=2^60)

Output
一行一个正整数表示正方形边长总和。

Sample Input
2 2
Sample Output
2

代码:
 

#include<iostream>
using namespace std;
 
long long f(long long a, long long b)
{
	if (a == 0)return 0;
	return f(b%a, a) + b / a*a;
}
 
int main()
{
	long long a, b;
	cin >> a >> b;
	cout << f(a, b) << endl;
	return 0;
}

BZOJ - 1411 硬币游戏

题目:


Description

Orez很喜欢玩游戏,他最近发明了一款硬币游戏。他在桌子的边缘上划分出2*n个位置并按顺时针把它们标号为1,2,……,2n,然后把n个硬币放在标号为奇数的位置上。接下来每次按如下操作:在任意两个硬币之间放上一个硬币,然后将原来的硬币拿走;所放硬币的正反面由它两边的两个硬币决定,若两个硬币均为正面朝上或反面朝上,则所放硬币为正面朝上,否则为反面朝上。 那么操作T次之后桌子边缘上硬币的情况会是怎样的呢?

Input

文件的第一行包含两个整数n和T。 接下的一行包含n个整数,表示最开始桌面边缘的硬币摆放情况,第i个整数ai表示第i个硬币摆放在2*i-1个位置上,ai=1表示正面朝上,ai=2表示反面朝上。

Output

文件仅包含一行,为2n个整数,其中第i个整数bi桌面边缘的第i个位置上硬币的情况,bi=1表示正面朝上,bi=2表示反面朝上,bi=0表示没有硬币。

Sample Input

10 5
2 2 2 1 1 1 1 1 1 2

Sample Output

0 1 0 1 0 1 0 1 0 2 0 1 0 2 0 1 0 1 0 1

数据范围
30%的数据 n≤1000 T≤1000
100%的数据 n≤100000 T≤2^60

把t分解成若干个2个幂的和

代码:
 

#include<iostream>
using namespace std;

int n, num[100000], nu[100000];

void f(long long k)
{
	for (int i = 0; i < n; i++)
		nu[i] = (num[i] + num[(i + k) % n]) % 2 + 1;
	for (int i = 0; i < n; i++)num[i] = nu[i];
}

void out(long long tt)
{
	for (int i = 0; i < n; i++)
	{
		if (tt % 2)cout << "0 ";
		cout << num[((i - tt / 2) % n + n) % n];
		if (tt % 2 == 0)cout << " 0";
		cout << ((n - i - 1) ? " " : "\n");
	}
}

int main()
{
	long long t, tt;
	cin >> n >> t;
	for (int i = 0; i < n; i++)cin >> num[i];
	tt = t;
	while (t)
	{
		f(t & -t);
		t &= t - 1;
	}
	out(tt);
	return 0;
}

BZOJ - 3517 翻硬币(异或)

题目:


Description

有一个n行n列的棋盘,每个格子上都有一个硬币,且n为偶数。每个硬币要么是正面朝上,要么是反面朝上。每次操作你可以选定一个格子(x,y),然后将第x行和第y列的所有硬币都翻面。求将所有硬币都变成同一个面最少需要的操作数。
Input

第一行包含一个正整数n。
接下来n行,每行包含一个长度为n的01字符串,表示棋盘上硬币的状态。
Output

仅包含一行,为最少需要的操作数。
Sample Input

4
0101
1000
0010
0101
Sample Output

2
Hint

【样例说明】

对(2,3)和(3,1)进行操作,最后全变成1。

【数据规模】

对于100%的数据,n ≤ 1,000。


分析:(以下6个数组都是0-1数组,S也是0或1)

假设输入矩阵是num[i][j],第i行的异或和是row[i],第j行的异或和是col[j](0<=i<n,0<=j<n)

要求的矩阵是xnum[i][j],第i行的异或和是xrow[i],第j行的异或和是xcol[j],n*n个xnum[i][j]的异或和为S

因为不知道最后是全部变成1还是全部变成0,所以有2种情况

第一种情况:

那么根据题意,num[i][j]^xrow[i]^xcol[j]^xnum[i][j]=0   ------(1)

将(1)式中的j取遍0至n-1,再将n个式子求异或,根据异或的交换性和结合性从而化简得到:

row[i]^(xrow[i]*n%2)^S^xrow[i]=0

因为n是偶数所以row[i]^S^xrow[i]=0   ------(2)

同理col[j]^S^xcol[j]=0   ------(3)

(1)(2)(3)式的异或和为num[i][j]^row[i]^col[j]^xnum[i][j]=0

即xnum[i][j]=num[i][j]^row[i]^col[j]

第二种情况:

与第一种情况同理,xnum[i][j]=num[i][j]^row[i]^col[j]^1

第一种情况和第二种情况刚好完全互补,其中1较少的那种就是结果

无论是第一种还是第二种,由num计算xnum的方法和由xnum计算num的方法是一样的,这是一种高度的对称性,这一点,和点亮所有的灯(https://blog.csdn.net/nameofcsdn/article/details/52100217)十分相似

代码:
 

#include <iostream>
using namespace std;

int num[1001][1001], row[1001], col[1001];

int main()
{
	int n, sum = 0;
	cin >> n;
	char c;
	for (int i = 0; i < n; i++)row[i] = col[i] = 0;
	for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)
	{
		cin >> c;
		num[i][j] = c - '0';
		row[i] += num[i][j], col[j] += num[i][j];
	}
	for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)
		sum += (row[i] + col[j] + num[i][j]) % 2;
	cout << ((sum * 2>n*n) ? n*n - sum : sum) << endl;
	return 0;
}

Celebration SPOJ - CELEBRATION

题目:

Today is Naruto’s birthday. To celebrate his birthday he and his friends are at Ichimaru’s ramen shop. Naruto has N friends. Each of them wants some number of ramen as birthday treat from Naruto. Let’s index his friends from 1 to N. The i-th of them wants Ai bowls of ramen. The price of each bowl is D dollars. Naruto has only K dollars. Sometimes it’s not enough and when he has less dollars than he needs to buy ramen for all of his friends, he borrows some dollar from Iruka Sensei.

Now given all this information you have to calculate the minimum amount of money Naruto needs to borrow from Iruka Sensei to buy ramen for all of his friends.

Input
The input set starts with a single line integer T (1<=T<=50) the number of test cases. T cases follow. Each case starts with an integer N (0<=N<=1000) denoting the number of Naruto`s friends. The second line of each case contains N space separated integers Ai (0<=Ai<=100000) denoting the number of bowls the i-th friend wants. The third line contains two integers K (0<=k<=10^9) denoting the amount of money Naruto has and D (0<=D<=1000), the price of each bowl.

Output
For each test case output one line “Case X: ” without the quotes where X is the case number starting from 1 and one integer, the minimum amount of money Naruto needs to borrow.

Example
Input:
2
3
1 2 3
5 1
2
2 2
4 2
Output:
Case 1: 1
Case 2: 4
彻底的水题
代码:

#include<iostream>
using namespace std;

int main()
{
    int T, n;
    cin >> T;
    for(int i = 1; i <= T; i++)
    {
        cin >> n;
        int s = 0, temp;
        while(n--)
        {
            cin >> temp;
            s += temp;
        }
        long long k, d;
        cin >> k >> d;
        d *= s;
        d -= k;
        if(d < 0)d = 0;
        cout <<"Case "<< i <<": "<< d << endl;
    }
    return 0;
}

HDU - 1128 Self Numbers

题目:


Description

In 1949 the Indian mathematician D.R. Kaprekar discovered a class of numbers called self-numbers. For any positive integer n, define d(n) to be n plus the sum of the digits of n. (The d stands for digitadition, a term coined by Kaprekar.) For example, d(75) = 75 + 7 + 5 = 87. Given any positive integer n as a starting point, you can construct the infinite increasing sequence of integers n, d(n), d(d(n)), d(d(d(n))), .... For example, if you start with 33, the next number is 33 + 3 + 3 = 39, the next is 39 + 3 + 9 = 51, the next is 51 + 5 + 1 = 57, and so you generate the sequence 
33, 39, 51, 57, 69, 84, 96, 111, 114, 120, 123, 129, 141, ... 

The number n is called a generator of d(n). In the sequence above, 33 is a generator of 39, 39 is a generator of 51, 51 is a generator of 57, and so on. Some numbers have more than one generator: for example, 101 has two generators, 91 and 100. A number with no generators is a self-number. There are thirteen self-numbers less than 100: 1, 3, 5, 7, 9, 20, 31, 42, 53, 64, 75, 86, and 97. 

Write a program to output all positive self-numbers less than or equal 1000000 in increasing order, one per line. 
Output

1
3
5
7
9
20
31
42
53
64
|
| <-- a lot more numbers
|
9903
9914
9925
9927
9938
9949
9960
9971
9982
9993
|
|
|
Sample Output

1
3
5
7
9
20
31
42
53
64
|
| <-- a lot more numbers
|
9903
9914
9925
9927
9938
9949
9960
9971
9982
9993
|
|
|

这个题目,主要就是筛法的思想

代码:
 

#include<iostream>
using namespace std;

int list[1000001];

void d(int i)
{
	int x1 = i % 10, x2 = i / 10 % 10, x3 = i / 100 % 10;
	int x4 = i / 1000 % 10, x5 = i / 10000 % 10, x6 = i / 100000;
	i += x1 + x2 + x3 + x4 + x5 + x6;
	if (i <= 1000000)list[i] = 0;
}

int main()
{
	for (int i = 1; i <= 1000000; i++)list[i] = 1;
	for (int i = 1; i < 1000000; i++)d(i);
	for (int i = 1; i <= 1000000; i++)if (list[i])cout << i << endl;
	return 0;
}

HDU - 1172 猜数字

题目:


Description

猜数字游戏是gameboy最喜欢的游戏之一。游戏的规则是这样的:计算机随机产生一个四位数,然后玩家猜这个四位数是什么。每猜一个数,计算机都会告诉玩家猜对几个数字,其中有几个数字在正确的位置上。 
比如计算机随机产生的数字为1122。如果玩家猜1234,因为1,2这两个数字同时存在于这两个数中,而且1在这两个数中的位置是相同的,所以计算机会告诉玩家猜对了2个数字,其中一个在正确的位置。如果玩家猜1111,那么计算机会告诉他猜对2个数字,有2个在正确的位置。 
现在给你一段gameboy与计算机的对话过程,你的任务是根据这段对话确定这个四位数是什么。 
Input

输入数据有多组。每组的第一行为一个正整数N(1<=N<=100),表示在这段对话中共有N次问答。在接下来的N行中,每行三个整数A,B,C。gameboy猜这个四位数为A,然后计算机回答猜对了B个数字,其中C个在正确的位置上。当N=0时,输入数据结束。 
Output

每组输入数据对应一行输出。如果根据这段对话能确定这个四位数,则输出这个四位数,若不能,则输出"Not sure"。 
Sample Input

6
4815 2 1
5716 1 0
7842 1 0
4901 0 0
8585 3 3
8555 3 2
2
4815 0 0
2999 3 3
0
Sample Output

3585
Not sure

想不到什么好的方法了,只能对每一组a,b,c,扫描10000个数,把不满足条件的都删掉。

N行之后,看还有多少满足条件的。

代码:
 

#include<iostream>
using namespace std;

int list[10000];
int a, b, c, k;
int na[4], nk[4];

void f(int i, int j)
{
	if (na[i] != nk[j] || na[i] < 0 || nk[j] < 0)return;
	b--;
	na[i] = -1, nk[j] = -1;
}

bool ok()
{
	na[0] = a / 1000, na[1] = a / 100 % 10, na[2] = a / 10 % 10, na[3] = a % 10;
	nk[0] = k / 1000, nk[1] = k / 100 % 10, nk[2] = k / 10 % 10, nk[3] = k % 10;
	for (int i = 0; i < 4; i++)if (na[i] == nk[i])c--;
	if (c)return false;
	for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++)f(i, j);
	if (b)return false;
	return true;
}

int main()
{
	int n;
	while (cin >> n)
	{
		if (n == 0)break;
		for (int i = 0; i < 10000; i++)list[i] = 1;
		while (n--)
		{
			cin >> a >> b >> c;
			int bb = b, cc = c;
			for (int i = 0; i < 10000; i++)
			{
				k = i;
				if (!ok())list[i] = 0;
				b = bb, c = cc;
			}
		}
		int sum = 0;
		for (int i = 0; i < 10000; i++)sum += list[i];
		if (sum != 1)cout << "Not sure" << endl;
		else for (int i = 0; i < 10000; i++)if (list[i])cout << i << endl;
	}
	return 0;
}

HDU - 1214 圆桌会议

题目:


Description

HDU ACM集训队的队员在暑假集训时经常要讨论自己在做题中遇到的问题.每当面临自己解决不了的问题时,他们就会围坐在一张圆形的桌子旁进行交流,经过大家的讨论后一般没有解决不了的问题,这也只有HDU ACM集训队特有的圆桌会议,有一天你也可以进来体会一下哦:),在一天在讨论的时候,Eddy想出了一个极为古怪的想法,如果他们在每一分钟内,一对相邻的两个ACM队员交换一下位子,那么要多少时间才能得到与原始状态相反的座位顺序呢?(即对于每个队员,原先在他左面的队员后来在他右面,原先在他右面的队员在他左面),这当然难不倒其他的聪明的其他队友们,马上就把这个古怪的问题给解决了,你知道是怎么解决的吗? 
Input

对于给定数目N(1<=N<=32767),表示有N个人,求要多少时间才能得到与原始状态相反的座位顺序(reverse)即对于每个人,原先在他左面的人后来在他右面,原先在他右面的人在他左面。 
Output

对每个数据输出一行,表示需要的时间(以分钟为单位) 
Sample Input

4
5
6
Sample Output

2
4
6

其实把一个圆反过来,最快的方法就是,把圆切成2条线段,分别把2个线段切开。

而其中最快的,就是把圆均分,一条是n/2,一条是(n-1)/2

长度为m的线段反过来最少需要的步数是m(m-1)/2

代码:
 

#include<iostream>
using namespace std;

int main()
{	
	int n;
	while (cin >> n)cout << n / 2 * ((n - 1) / 2) << endl;
}

HDU - 1270 小希的数表

题目:


Gardon昨天给小希布置了一道作业,即根据一张由不超过5000的N(3<=N<=100)个正整数组成的数表两两相加得到N*(N-1)/2个和,然后再将它们排序。例如,如果数表里含有四个数1,3,4,9,那么正确答案是4,5,7,10,12,13。小希做完作业以后出去玩了一阵,可是下午回家时发现原来的那张数表不见了,好在她做出的答案还在,你能帮助她根据她的答案计算出原来的数表么? 
Input
包含多组数据,每组数据以一个N开头,接下来的一行有按照大小顺序排列的N*(N-1)/2个数,是小希完成的答案。文件最后以一个0结束。 
假设输入保证解的存在性和唯一性。 
Output
对于每组数据,输出原来的数表。它们也应当是按照顺序排列的。 
Sample Input
4
4 5 7 10 12 13
4
5 6 7 8 9 10
0
Sample Output
1 3 4 9
2 3 4 6

对于N个数,有n=N*(N-1)/2个和

这个题目的难点在于,这n个和可能有一些是一样的

首先注意到,n个和中,第一个一定是ans[1]+ans[2],ans即为要求的答案

第二个和一定是ans[1]+ans[3]

第三个和可能是ans[2]+ans[3],但是也可能是ans[1]+ans[4]

实际上,ans[2]+ans[3]出现的位置(key)可能是3到N

只要枚举key,就能用方程sum[1]+sum[2]-sum[key]=ans[1]*2求出ans[1]

之所以说是方程,是因为在直接除2之前,需要判断奇偶性

得到了ans[1]之后,就可以算出所有的数

这个过程大致可以总结为:

先求出ans[2],再add(2),再求出ans[3],再add(3),再求出ans[4],再add(4)......

add函数是每次求出一个ans[i]之后,把前i-1个数和ans[i]的i-1个和删掉

那么剩下的所有和之中,最小的就是ans[1]+ans[i+1]了,如此即可继续求ans[i+1]

代码:
 

#include<iostream>
using namespace std;
 
int N, n, key, sum[5000], ans[101], minn;
 
int look(int s)	//寻找第一个前缀为s且后缀不为key的sum[i]的i
{
	int low = 1, high = n, mid;
	while (low < high - 1)
	{
		mid = (low + high) / 2;
		if (sum[mid] / 1000>=s)high = mid;
		else low = mid;
	}
	if (sum[low] / 1000 != s)low = high;
	if (sum[low] / 1000 != s)return 0;
	while (sum[low] % 1000 == key && low < n && sum[low + 1] / 1000 == sum[low] / 1000)low++;
	if (sum[low] % 1000 == key)return 0;
	return low;
}
 
bool add(int d)//新增ans[d],更新sum
{
	for (int i = 1; i<d; i++)
	{
		int k = look(ans[i] + ans[d]);
		if (k == 0)return false;
		sum[k] = sum[k] / 1000 * 1000 + key;
	}
	return true;
}
 
bool solve(int d)
{
	if (d > N)
	{
		for (int i = 1; i <= N; i++)cout << ans[i] << ((i < N) ? " " : "\n");
		return true;
	}
	while (sum[minn] % 1000 == key)minn++;
	ans[d] = sum[minn]/1000 - ans[1];
	if (!add(d))return false;
	return solve(d + 1);
}
 
int main()
{
	while (cin >> N)
	{
		if (N == 0)break;
		n = N*(N - 1) / 2;
		sum[0] = 0;
		for (int i = 1; i <= n; i++)
		{
			cin >> sum[i];
			sum[i] *= 1000;
		}
		for (key = 3; key <= N; key++)
		{
			if ((sum[1] + sum[2] - sum[key]) / 1000 % 2)continue;
			ans[1] = (sum[1] + sum[2] - sum[key]) / 2000;
			bool flag = true;
			for (int i = 2; i <= key && flag; i++)
			{
				ans[i] = sum[i - 1]/1000 - ans[1];
				if (!add(i))flag = false;
			}
			if (!flag)continue;
			minn = 1;
			if (solve(key+1))break;
		}
	}
	return 0;
}

HDU - 1717 小数化分数2

题目:


Ray 在数学课上听老师说,任何小数都能表示成分数的形式,他开始了化了起来,很快他就完成了,但他又想到一个问题,如何把一个循环小数化成分数呢? 
请你写一个程序不但可以将普通小数化成最简分数,也可以把循环小数化成最简分数。 
Input
第一行是一个整数N,表示有多少组数据。 
每组数据只有一个纯小数,也就是整数部分为0。小数的位数不超过9位,循环部分用()括起来。
Output
对每一个对应的小数化成最简分数后输出,占一行。
Sample Input
3
0.(4)
0.5
0.32(692307)
Sample Output
4/9
1/2
17/52


因为保证了是纯小数,所以输出的格式就是固定的,不存在整数的情况
因为保证了小数部分不超过9位,所以整个过程都可以用int,不会溢出

代码:

#include<iostream>
#include<string.h>
using namespace std;
 
int gcd(int a, int b)
{
	if (b)return gcd(b, a%b);
	return a;
}
 
void out(int zi, int mu)
{
	int g = gcd(zi, mu);
	cout << zi / g << '/' << mu / g << endl;
}
 
int main()
{
	int n, a, b, la, lb;
	char s[20];
	cin >> n;
	while (n--)
	{
		cin >> s;
		int l = strlen(s), k = -1;
		for (int i = 0; i < l; i++)if (s[i] == '(')k = i;
		a = 0, b = 0, la = 1, lb = 1;
		if (k == -1)
		{
			for (int i = 2; i < l; i++)a = a * 10 + s[i] - '0', la *= 10;
			out(a, la);
			continue;
		}
		for (int i = 2; i < k; i++)a = a * 10 + s[i] - '0', la *= 10;
		for (int i = k + 1; i < l - 1; i++)b = b * 10 + s[i] - '0', lb *= 10;
		out((lb - 1)*a + b, (lb - 1)*la);
	}
	return 0;
} 

HDU - 2006 求奇数的乘积

题目:


给你n个整数,求他们中所有奇数的乘积。
Input
输入数据包含多个测试实例,每个测试实例占一行,每行的第一个数为n,表示本组数据一共有n个,接着是n个整数,你可以假设每组数据必定至少存在一个奇数。
Output
输出每组数中的所有奇数的乘积,对于测试实例,输出一行。
Sample Input
3 1 2 3
4 2 3 4 5
Sample Output
3
15

代码:
 

#include<iostream>
using namespace std;
 
int main()
{
	int n, a;
	while (cin >> n)
	{
		int ans = 1;
		while (n--)
		{
			cin >> a;
			if (a % 2)ans *= a;
		}
		cout << ans << endl;
	}
	return 0;
}

HDU - 2010 水仙花数(CSU 1261)

题目:


Description

春天是鲜花的季节,水仙花就是其中最迷人的代表,数学上有个水仙花数,他是这样定义的: 
“水仙花数”是指一个三位数,它的各位数字的立方和等于其本身,比如:153=1^3+5^3+3^3。 
现在要求输出所有在m和n范围内的水仙花数。 
Input

输入数据有多组,每组占一行,包括两个整数m和n(100<=m<=n<=999)。
Output

对于每个测试实例,要求输出所有在给定范围内的水仙花数,就是说,输出的水仙花数必须大于等于m,并且小于等于n,如果有多个,则要求从小到大排列在一行内输出,之间用一个空格隔开; 
如果给定的范围内不存在水仙花数,则输出no; 
每个测试实例的输出占一行。
Sample Input

100 120
300 380
Sample Output

no
370 371

代码:
 

#include<iostream>
using namespace std;

//bool narcissus(int n)
//{
//	int a = n / 100, b = n / 10 % 10, c = n % 10;
//	return a*a*a + b*b*b + c*c*c == a * 100 + b * 10 + c;
//}
int naricissus[4] = { 153,370,371,407 };

int main()
{
	int m, n;
	while (cin >> m >> n)
	{
		bool b = true;
		for (int i = 0; i < 4; i++)if (m <= naricissus[i] && naricissus[i] <= n)
		{
			if (!b)cout << " ";
			cout << naricissus[i];
			b = false;
		}
		if (b)cout << "no";
		cout << endl;
	}
	return 0;
}

HDU - 5272 Dylans loves numbers

题目:


Description

Who is Dylans?You can find his ID in UOJ and Codeforces. 
His another ID is s1451900 in BestCoder. 

And now today's problems are all about him. 

Dylans is given a number  . 
He wants to find out how many groups of "1" in its Binary representation. 

If there are some "0"(at least one)that are between two "1", 
then we call these two "1" are not in a group,otherwise they are in a group.
Input

In the first line there is a number  . 

 is the test number. 

In the next   lines there is a number  . 

Output

For each test case,output an answer.
Sample Input

1
5
Sample Output

2

求1个数的二进制有多少段连续的1

代码:
 

#include<iostream>
#include<stdio.h>
using namespace std;
 
int main()
{
	int t, r;
	cin >> t;
	long long n;
	while (t--)
	{
		cin >> n;
		r = 0;
		while (n)
		{
			while (n % 2 == 0)n /= 2;
			while (n % 2)n /= 2;
			r++;
		}
		cout << r << endl;
	}
	return 0;
}

这么简单就懒得解释了。

HDU - 5583 Kingdom of Black and White

题目:

Description

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

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

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

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

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

Every test case only contains a string with length  , including only   (representing a black frog) and   (representing a white frog). 

       . 

 for 60% data,         . 

 for 100% data,        . 

 the string only contains 0 and 1.
Output

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

2
000011
0101
Sample Output

Case #1: 26
Case #2: 10

首先, 不可能把一个长x+1+y的串拆开成x和1和y的串,因为(x+1+y)^2>x^2+1+y^2

所以,要不不修改任何数字,要不修改的那个数字就是处于原串的边缘。

所以,实际上只有2种情况,

第一,x^2+y^2变成(x-1)^2+(y+1)^2或者(x+1)^2+(y-1)^2,所以增量是2|x-y|+2

第二,x^2+1+y^2变成(x+1+y)^2,增量为2(x+y)+2

注意,第一种的是x和y相邻,第二种的是x和y之间夹了一个1。

只要按照顺序统计每一段的长度s,同时把s*s求和到sum里面,最后sum就是可能的解。

同时还要记录2种增量,保持刷新留下最大值,最后加到sum里面去就大功告成了。

代码:

#include<iostream>
#include<string.h>
using namespace std;
 
char c[100001];
 
int main()
{
	int t;
	cin >> t;
	int l;
	long long s, sum;
	char ch;
	cin.getline(c, 100001);
	long long temps, dif, temptemps, dsum;
	for (int i = 1; i <= t; i++)
	{
		cin.getline(c, 100001);
		l = strlen(c);
		c[l] = '2';
		ch = '2';
		s = 0;
		sum = 0;
		temps = 0;
		dif = 0;
		dsum = 0;
		for (int i = 0; i <= l; i++)
		{
			if (c[i] != ch)
			{
				if (temps == 1 && dsum < temptemps + s + temptemps*s)
				dsum = temptemps + s + temptemps*s;
				if (s && temps)
				{
					if (dif < s - temps)dif = s - temps;
					if (dif < temps - s)dif = temps - s;
				}
				temptemps = temps;
				temps = s;				
				sum += s*s;
				s = 1;
				ch = c[i];
			}
			else s++;
		}
		if(temptemps)dif++;
		sum += ((dif > dsum) ? dif : dsum) * 2;
		cout << "Case #" << i << ": " << sum<< endl;
	}
	return 0;
}

HDU - 5832 A water problem

8.14日网络赛第1题

题目:

Description

Two planets named Haha and Xixi in the universe and they were created with the universe beginning. 

There is   days in Xixi a year and   days in Haha a year. 

Now you know the days   after Big Bang, you need to answer whether it is the first day in a year about the two planets.
Input

There are several test cases(about   huge test cases). 

For each test, we have a line with an only integer  , the length of   is up to  .
Output

For the i-th test case, output Case #i: , then output "YES" or "NO" for the answer.
Sample Input

10001
0
333
Sample Output

Case #1: YES
Case #2: YES
Case #3: NO

直接一位一位地算

我们队伍的代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#define N 10000001
char str[N];
int len;
int i;
int mod;
long long ans;
int ca;
int main()
{
    mod = 10001;
    while(scanf("%s", str) != EOF)
    {
        ca++;
        ans = 0;
        len = strlen(str);
        for(i = 0; i < len; i++)ans = (ans * 10 + str[i]-'0') % mod;
        if(ans == 0) printf("Case #%d: YES\n", ca);
        else printf("Case #%d: NO\n", ca);
    }
    return 0;
}

虽然很慢,但是AC了

HDU - 1465 不容易系列之一(错排数)

题目:

大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了! 
做好“一件”事情尚且不易,若想永远成功而总从不失败,那更是难上加难了,就像花钱总是比挣钱容易的道理一样。 
话虽这样说,我还是要告诉大家,要想失败到一定程度也是不容易的。比如,我高中的时候,就有一个神奇的女生,在英语考试的时候,竟然把40个单项选择题全部做错了!大家都学过概率论,应该知道出现这种情况的概率,所以至今我都觉得这是一件神奇的事情。如果套用一句经典的评语,我们可以这样总结:一个人做错一道选择题并不难,难的是全部做错,一个不对。 

不幸的是,这种小概率事件又发生了,而且就在我们身边: 
事情是这样的——HDU有个网名叫做8006的男性同学,结交网友无数,最近该同学玩起了浪漫,同时给n个网友每人写了一封信,这都没什么,要命的是,他竟然把所有的信都装错了信封!注意了,是全部装错哟! 

现在的问题是:请大家帮可怜的8006同学计算一下,一共有多少种可能的错误方式呢?
Input输入数据包含多个多个测试实例,每个测试实例占用一行,每行包含一个正整数n(1<n<=20),n表示8006的网友的人数。Output对于每行输入请输出可能的错误方式的数量,每个实例的输出占用一行。Sample Input
2
3
Sample Output
1
2


就是求错排数,利用递推式即可

代码:
 

#include<iostream>
using namespace std;
 
int main()
{
	long long n, ans[21];
	while (cin >> n)
	{
		ans[1] = 0, ans[2] = 1;
		for (int i = 3; i <= n; i++)ans[i] = (ans[i - 1] + ans[i - 2])*(i - 1);
		cout << ans[n] << endl;
	}	
	return 0;
}

HDU - 2042 不容易系列之二

题目:

你活的不容易,我活的不容易,他活的也不容易。不过,如果你看了下面的故事,就会知道,有位老汉比你还不容易。 

重庆市郊黄泥板村的徐老汉(大号徐东海,简称XDH)这两年辛辛苦苦养了不少羊,到了今年夏天,由于众所周知的高温干旱,实在没办法解决牲畜的饮水问题,就决定把这些羊都赶到集市去卖。从黄泥板村到交易地点要经过N个收费站,按说这收费站和徐老汉没什么关系,但是事实却令徐老汉欲哭无泪: 

(镜头回放) 

近景:老汉,一群羊 
远景:公路,收费站 

...... 

收费员(彬彬有礼+职业微笑):“老同志,请交过路费!” 

徐老汉(愕然,反应迟钝状):“锅,锅,锅,锅-炉-费?我家不烧锅炉呀?” 

收费员(职业微笑依然):“老同志,我说的是过-路-费,就是你的羊要过这个路口必须交费,understand?” 

徐老汉(近镜头10秒,嘴巴张开):“我-我-我知道汽车过路要收费,这羊也要收费呀?” 

收费员(居高临下+不解状):“老同志,你怎么就不明白呢,那么我问你,汽车几个轮子?” 

徐老汉(稍放松):“这个我知道,今天在家里我孙子还问我这个问题,4个!” 

收费员(生气,站起):“嘿!老头,你还骂人不带脏字,既然知道汽车四个轮子,难道就不知道这羊有几条腿吗?!” 

徐老汉(尴尬,依然不解状):“也,也,也是4个呀,这有关系吗?” 

收费员(生气,站起):“怎么没关系!我们头说了,只要是4条腿的都要收费!” 

...... 

(画外音) 

由于徐老汉没钱,收费员就将他的羊拿走一半,看到老汉泪水涟涟,犹豫了一下,又还给老汉一只。巧合的是,后面每过一个收费站,都是拿走当时羊的一半,然后退还一只,等到老汉到达市场,就只剩下3只羊了。 

你,当代有良知的青年,能帮忙算一下老汉最初有多少只羊吗? 
Input输入数据第一行是一个整数N,下面由N行组成,每行包含一个整数a(0<a<=30),表示收费站的数量。 
Output对于每个测试实例,请输出最初的羊的数量,每个测试实例的输出占一行。 
Sample Input
2
1
2
Sample Output
4
6


可以算出来答案是2^n+2

代码:
 

#include<iostream>
using namespace std;
 
int main()
{
	int a;
	cin >> a;
	while (cin >> a)cout << (1 << a) + 2 << endl;
	return 0;
}

HDU - 2045 不容易系列之(3)—— LELE的RPG难题

题目:

人称“AC女之杀手”的超级偶像LELE最近忽然玩起了深沉,这可急坏了众多“Cole”(LELE的粉丝,即"可乐"),经过多方打探,某资深Cole终于知道了原因,原来,LELE最近研究起了著名的RPG难题: 

有排成一行的n个方格,用红(Red)、粉(Pink)、绿(Green)三色涂每个格子,每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色.求全部的满足要求的涂法. 

以上就是著名的RPG难题. 

如果你是Cole,我想你一定会想尽办法帮助LELE解决这个问题的;如果不是,看在众多漂亮的痛不欲生的Cole女的面子上,你也不会袖手旁观吧? 

Input输入数据包含多个测试实例,每个测试实例占一行,由一个整数N组成,(0<n<=50)。 
Output对于每个测试实例,请输出全部的满足要求的涂法,每个实例的输出占一行。 
Sample Input
1
2
Sample Output
3
6


代码:
 

#include<iostream>
using namespace std;
 
int main()
{
	long long n, ans[51] = { 0,3,6,6 };
	for (int i = 4; i < 51; i++)ans[i] = ans[i - 1] + ans[i - 2] * 2;
	while (cin >> n)cout << ans[n] << endl;
	return 0;
}

HDU - 2049 不容易系列之(4)——考新郎

题目:

国庆期间,省城HZ刚刚举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做"考新郎",具体的操作是这样的: 

首先,给每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排; 
然后,让各位新郎寻找自己的新娘.每人只准找一个,并且不允许多人找一个. 
最后,揭开盖头,如果找错了对象就要当众跪搓衣板... 

看来做新郎也不是容易的事情... 

假设一共有N对新婚夫妇,其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能. 
Input输入数据的第一行是一个整数C,表示测试实例的个数,然后是C行数据,每行包含两个整数N和M(1<M<=N<=20)。 
Output对于每个测试实例,请输出一共有多少种发生这种情况的可能,每个实例的输出占一行。 
Sample Input
2
2 2
3 2
Sample Output
1
3


答案就是m的错排数再乘组合数C(n,m)
 

#include<iostream>
using namespace std;
 
long long c(int n, int m)
{
	if (m > n / 2)return c(n, n - m);
	if (m == 0)return 1;
	long long ans = 1;
	for (int i = n; i > n - m; i--)ans *= i;
	for (int i = m; i > 1; i--)ans /= i;
	return ans;
}
 
int main()
{
	long long n, m, ans[21];
	cin >> n;
	while (cin >> n >> m)
	{
		ans[1] = 0, ans[2] = 1;
		for (int i = 3; i <= m; i++)ans[i] = (ans[i - 1] + ans[i - 2])*(i - 1);
		cout << ans[m] * c(n, m) << endl;
	}
	return 0;
}

HUST - 1228 区间合并

题目:


区间合并
Input
题目是由多组输入组成 给定n(3<=n<=50000)个闭区间[ai, bi](1 <=i <=n, ai,bi均为非负整数),将这些区间合并为不相交的闭区间。输入文件的第一行包含一个整数n,为区间的数目。以下有n行,每行各包括两个空格分隔的整数ai 和 bi,表示一个区间[ai, bi](0 <= ai,bi <=1000000)。 n=0 表示输入文件的结束。
Output
计算结果写在标准输出上,各区间按照升序排列输出。每一行包含两个用空 格分开的整数,分别描述一个区间的上下界。 各组输入之间 用一个空行隔开
Sample Input
5
5 6
1 4
10 10
6 9
8 10
3
1 2
3 4
2 10
0
Sample Output
1 4
5 10

1 10

代码:
 

#include<iostream>
#include <stdio.h>
#include<algorithm>
using namespace std;
 
struct node
{
	int a, b;
};
 
node p[50001];
 
bool cmp(node p1,node p2)
{
	return p1.a < p2.a;
} 
int main()
{
	int f = 0;
	int n;
	while (scanf("%d",&n))
	{
		if (n == 0)break;
		if (f++)printf("\n");
		for (int i = 0; i < n; i++)scanf("%d%d", &p[i].a, &p[i].b);
		sort(p, p + n, cmp);
		int low = p[0].a, high = p[0].b;
		for (int i = 0; i < n; i++)
		{
			if(high<p[i].a)
			{
				printf("%d %d\n", low, high);
				low = p[i].a;
			}
			if (high < p[i].b)high = p[i].b;
		}
		printf("%d %d\n", low, high);
	}
	return 0;
}

HYSBZ - 1599 笨重的石子

题目:

Description

贝西喜欢棋盘游戏和角色扮演类游戏所以她说服Farmer John把她带到玩具店,在那里,她购买了三个不同的骰子,这三个质量均匀的骰子,分别有S1,S2,S3个面。(2 <= S1 <= 20; 2 <= S2 <= 20; 2 <= S3 <= 40). 贝西掷啊掷啊掷啊,想要知道出现几率最大的和是多少。 问题给出三个骰子的面数,让你求出出现几率最大的和是多少。如果有很多种和出现的几率相同,那么就输出小的那一个。
Input

*第一行:三个由空格隔开的整数:s1,s2,s3
Output

*第一行:所要求的解
Sample Input

3 2 3
Sample Output

5

代码:

#include<iostream>
using namespace std;

int f(int s1, int s2, int s3)
{
	if (s1 % 2)return (s2 + s3) / 2 + s1 / 2 + 2;
	if (s2 % 2)return (s1 + s3) / 2 + s2 / 2 + 2;
	return (s1 + s2) / 2 + (s3 + 1) / 2 + 1;
}

int main()
{
	int s1, s2, s3;
	cin >> s1 >> s2 >> s3;
	cout << f(s1, s2, s3) << endl;
	return 0;
}

这个题目提交不了了,不过感觉代码应该没错吧。

OpenJ_Bailian - 2733 判断闰年

题目:

Description

判断某年是否是闰年。
Input

输入只有一行,包含一个整数a(0 < a < 3000)
Output

一行,如果公元a年是闰年输出Y,否则输出N
Sample Input

2006
Sample Output

N
Hint

公历纪年法中,能被4整除的大多是闰年,但能被100整除而不能被400整除的年份不是闰年, 能被3200整除的也不是闰年,如1900年是平年,2000年是闰年,3200年不是闰年。

这个题目的提示有亮点

我也不知道真的假的,好像没有听说过这个规矩。

不过无所谓,这个题目专门控制了a<3000

代码:
 

#include<iostream>
using namespace std;
 
char f(int n)
{
	if (n % 4)return 'N';
	if (n % 100)return 'Y';
	if (n % 400)return 'N';
	//if (n % 3200)
		return 'Y';
	//return 'N';
}
 
int main()
{
	int a;
	cin >> a;
	cout << f(a) << endl;
	return 0;
}

POJ - 1032 Parliament( 把正整数n表示成若干个不同的正整数的和,求积的最大值)

题目:


Description

New convocation of The Fool Land's Parliament consists of N delegates. According to the present regulation delegates should be divided into disjoint groups of different sizes and every day each group has to send one delegate to the conciliatory committee. The composition of the conciliatory committee should be different each day. The Parliament works only while this can be accomplished. 
You are to write a program that will determine how many delegates should contain each group in order for Parliament to work as long as possible. 
Input

The input file contains a single integer N (5<=N<=1000 ).
Output

Write to the output file the sizes of groups that allow the Parliament to work for the maximal possible time. These sizes should be printed on a single line in ascending order and should be separated by spaces.
Sample Input

7
Sample Output

3 4

代码:
 

#include<iostream>
using namespace std;

int main()
{
	int n, k = 1, s = 0, r;
	cin >> n;
	while (k++)
	{
		s += k;
		if (s > n)
		{
			s -= k--;
			break;
		}
	}
	r = n - s;
	if (r == k)
	{
		for (int i = 3; i <= k; i++)cout << i << " ";
		cout << k + 2 << endl;
	}
	else
	{
		for (int i = 2; i <= k - r; i++)
		{
			cout << i;
			if (i < k)cout << " ";
		}
		for (int i = k - r + 1; i <= k; i++)
		{
			cout << i + 1;
			if (i < k)cout << " ";
		}
		cout << endl;
	}
	return 0;
}

思路和原理: 把正整数n表示成若干个不同的正整数的和,求积的最大值

POJ - 2926 Requirements

题目:


Description

An undergraduate student, realizing that he needs to do research to improve his chances of being accepted to graduate school, decided that it is now time to do some independent research. Of course, he has decided to do research in the most important domain: the requirements he must fulfill to graduate from his undergraduate university. First, he discovered (to his surprise) that he has to fulfill 5 distinct requirements: the general institute requirement, the writing requirement, the science requirement, the foreign-language requirement, and the field-of-specialization requirement. Formally, a requirement is a fixed number of classes that he has to take during his undergraduate years. Thus, for example, the foreign language requirement specifies that the student has to take 4 classes to fulfill this requirement: French I, French II, French III, and French IV. Having analyzed the immense multitude of the classes that need to be taken to fulfill the different requirements, our student became a little depressed about his undergraduate university: there are so many classes to take…

Dejected, the student began studying the requirements of other universities that he might have chosen after high school. He found that, in fact, other universities had exactly the same 5 requirements as his own university. The only difference was that different universities had different number of classes to be satisfied in each of the five requirement.

Still, it appeared that universities have pretty similar requirements (all of them require a lot of classes), so he hypothesized that no two universities are very dissimilar in their requirements. He defined the dissimilarity of two universities X and Y as |x1 − y1| + |x2− y2| + |x3 − y3| + |x4 − y4| + |x5 − y5|, where an xi (yi) is the number of classes in the requirement i of university X (Y) multiplied by an appropriate factor that measures hardness of the corresponding requirement at the corresponding university.

Input

The first line of the input file contains an integer N (1 ≤ N ≤ 100 000), the number of considered universities. The following Nlines each describe the requirements of a university. A university X is described by the five non-negative real numbers x1 x2 x3 x4x5.

Output

On a single line, print the dissimilarity value of the two most dissimilar universities. Your answer should be rounded to exactly two decimal places.

Sample Input

3
2 5 6 2 1.5
1.2 3 2 5 4
7 5 3 2 5
Sample Output

12.80

点(x1,x2,x3,x4,x5)和(y1,y2,y3,y4,y5)的曼哈顿距离是:

a1(x1-y1)+a2(x2-y2)+a3(x3-y3)+a4(x4-y4)+a5(x5-y5),其中a取1或者-1

在这样的32个组合中,最大的就是曼哈顿距离了。

用了一点点状态压缩的技巧,用0-31表示这32个二进制5位数,然后把1,0变成1,-1

这样就取遍了32个组合。

代码:

#include<iostream>
#include<limits>
using namespace std;

double list[32];
double maxs[32];
double mins[32];

int main()
{
	for (int i = 0; i < 32; i++)maxs[i] = numeric_limits<double>::max()*-1;
	for (int i = 0; i < 32; i++)mins[i] = numeric_limits<double>::max();
	int n;
	cin >> n;
	double x;
	while (n--)
	{
		for (int i = 0; i < 32; i++)list[i] = 0;
		for (int k = 0; k < 5; k++)
		{
			cin >> x;
			for (int i = 0; i < 32; i++)list[i] += x*((i >> k) % 2 * 2 - 1);
		}
		for (int i = 0; i < 32; i++)if (list[i]>maxs[i])maxs[i] = list[i];
		for (int i = 0; i < 32; i++)if (list[i]<mins[i])mins[i] = list[i];
	}
	double m = 0;
	for (int i = 0; i < 32; i++)if (maxs[i] - mins[i]>m)m = maxs[i] - mins[i];
	printf("%.2f\n", m);
	return 0;
}

POJ 2299 Ultra-QuickSort

题目:

Description

In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence  9 1 0 5 4 ,Ultra-QuickSort produces the output  0 1 4 5 9 .
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.
Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.
Sample Input

5
9
1
0
5
4
3
1
2
3
0
Sample Output

6
0

题意很好理解,输入一个数列,输出它的逆序数。

我的原始代码(超时):
 

#include<iostream>
using namespace std;

int n;
int c[500005];
int num[500005];

int sum(int i)
{
	int s = 0;
	while (i)
	{
		s += c[i];
		i -= (i&(-i));
	}
	return s;
}

void add(int i, int x)
{
	while (i <= n)
	{
		c[i] += x;
		i += (i&(-i));
	}
}

int findmax()
{
	int max = 1;
	for (int j = 2; j <= n; j++)if (num[max] < num[j])max = j;
	return max;
}

int main()
{	
	ios_base::sync_with_stdio(false);
	long long s;
	while (cin >> n)
	{
		if (n == 0)break;
		for (int i = 1; i <= n; i++)
		{
			cin >> num[i];
			c[i] = 0;
		}
		s = 0;
		for (int i = 1; i <= n; i++)
		{
			int j = findmax();
			num[j] = -1;
			s += sum(j);
			add(j, 1);
		}
		cout << s << endl;
	}
	return 0;
}

很明显它的时间是n*n,所以超时了。

但是好在思路差的不是很多,稍微改了下就对了。

代码:

#include<iostream>
#include<algorithm>
using namespace std;
 
struct node
{
	int num;
	int index;
};
 
int n;
int c[500005];
node nod[500005];
 
bool cmp(node a, node b)
{
	return a.num > b.num;
}
 
int sum(int i)
{
	int s = 0;
	while (i)
	{
		s += c[i];
		i -= (i&(-i));
	}
	return s;
}
 
void add(int i, int x)
{
	while (i <= n)
	{
		c[i] += x;
		i += (i&(-i));
	}
}
 
int main()
{	
	ios_base::sync_with_stdio(false);
	long long s;
	while (cin >> n)
	{
		if (n == 0)break;
		for (int i = 1; i <= n; i++)
		{
			cin >> nod[i].num;
			nod[i].index = i;
			c[i] = 0;
		}
		s = 0;
		sort(nod + 1, nod + 1 + n, cmp);
		for (int i = 1; i <= n; i++)
		{
			int j = nod[i].index;
			s += sum(j);
			add(j, 1);
		}
		cout << s << endl;
	}
	return 0;
}

这个虽然过了,但是很慢,我猜想手写快速排序或者归并排序应该会比较快。

普通的归并排序,只需要加一句sum += mid - i + 1;就可以变成边排序边统计逆序数。

代码:

#include<iostream>
using namespace std;
 
int n;
long long sum;
int num[500005];
int copynum[500005];
 
void merge(int low, int high)
{
	int mid = (low + high) / 2;
	int i = low, j = mid + 1, k = low;
	while (i <= mid && j <= high)
	{
		if (num[i] < num[j])copynum[k++] = num[i++];
		else
		{
			copynum[k++] = num[j++];
			sum += mid - i + 1;
		}
	}
	while (i <= mid)copynum[k++] = num[i++];
	while (j <= high)copynum[k++] = num[j++];
	for (int i = low; i <= high; i++)num[i] = copynum[i];
}
 
void sort(int low, int high)
{
	if (low == high)return;
	int mid = (low + high) / 2;
	sort(low, mid);
	sort(mid + 1, high);
	merge(low, high);
}
 
int main()
{	
	ios_base::sync_with_stdio(false);
	while (cin >> n)
	{
		if (n == 0)break;
		for (int i = 1; i <= n; i++)cin >> num[i];
		sum = 0;
		sort(1, n);
		cout << sum << endl;
	}
	return 0;
}

POJ 2531 Network Saboteur

题目:

Description

A university network is composed of N computers. System administrators gathered information on the traffic between nodes, and carefully divided the network into two subnetworks in order to minimize traffic between parts. 
A disgruntled computer science student Vasya, after being expelled from the university, decided to have his revenge. He hacked into the university network and decided to reassign computers to maximize the traffic between two subnetworks. 
Unfortunately, he found that calculating such worst subdivision is one of those problems he, being a student, failed to solve. So he asks you, a more successful CS student, to help him. 
The traffic data are given in the form of matrix C, where Cij is the amount of data sent between ith and jth nodes (Cij = Cji, Cii = 0). The goal is to divide the network nodes into the two disjointed subsets A and B so as to maximize the sum ∑Cij (i∈A,j∈B).
Input

The first line of input contains a number of nodes N (2 <= N <= 20). The following N lines, containing N space-separated integers each, represent the traffic matrix C (0 <= Cij <= 10000). 
Output file must contain a single integer -- the maximum traffic between the subnetworks. 
Output

Output must contain a single integer -- the maximum traffic between the subnetworks.
Sample Input

3
0 50 30
50 0 40
30 40 0
Sample Output

90

这个题目,我从头到尾都感觉像是动态规划。

虽然没有用数组记录(我觉得这是我的时间非常长,接近2秒,快超时了,的重要原因),但是在函数递归调用的过程中,还是避免了一些重复计算的,不过也产生了一些不必要的计算,我没有想到这样居然反而特别慢。

为了实现这种思想,我用了二进制和划分的对应,比如100000对应划分{ {a}{bcdef}},010111对应划分{ {bdef}{ac}},等等。

应该就是因为有这种附加运算,才会导致运行时间比较长。

还有一个因素,我是把所有的情况都精确求出来了,中途没有估值剪枝什么的。

最开始的时候我的思路是不用二维数组记录,只用2个一维数组,边输入数据边记录输入矩阵的上三角部分的行和和列和,

我以为结果是可以用这些行和和列和表示的,后来写完一运行才发现算的不对。

代码:

#include<iostream>
using namespace std;
 
int maxx;
int place(int n, int **list, int nn)
{
	if (n == 0)return 0;
	if (n == 1)
	{
		int result = 0;
		for (int i = 0; i < n; i++)result += list[0][i];
		return result;
	}
	int d = 0, m = n;
	while (m)
	{
		d++;
		m /= 2;
	}
	m = 1;
	for (int i = 0; i < d - 1; i++)m *= 2;
	int r = place(n - m, list, nn);
	for (int i = 0; i < nn; i++)
	{
		if (n % 2)r -= list[i][d - 1];
		else r += list[i][d - 1];
		n /= 2;
	}
	if (maxx < r)maxx = r;
	return r;
}
 
int main()
{
	int n;
	while (cin >> n)
	{
		int **list = new int*[n];
		for (int i = 0; i < n; i++)
		{
			list[i] = new int[n];
			for (int j = 0; j < n; j++)cin >> list[i][j];
		}
		maxx = 0;
		int m = 1;
		for (int i = 0; i < n-1; i++)m *= 2;
		for (int i = m; i < m * 2; i++)place(i, list, n);
		cout << maxx << endl;
	}
	return 0;
}

之所以用maxx而不是max是因为OJ里面的编译器不一样,它会提示命名冲突。

SGU139:Help Needed(拼图)

题目:

Description

Little Johnny likes puzzles a lot! Just a few days ago, he found out about the 'traditional' 4x4 puzzle. For this puzzle, you have all the numbers from 0 to 15 arranged in 4 rows and 4 columns. You are allowed to switch two adjacent elements (horizontally or vertically), only if one of them has the value 0. The purpose of the puzzle is to reach the following final state:

                            1  2   3   4 
                            5  6   7   8 
                            9  10  11  12 
                           13  14  15  0

Given the initial state of the puzzle, you have to decide whether there exists a sequence of moves which brings the puzzle into the final state.

Input

The input will consist of  4 lines, each of them containing 4 integers, describing the initial state of the puzzle.

Output

For every initial state, you should print "YES" if the final state can be reached after several moves or "NO", if such a thing is impossible.

Sample Input #1

1 2 3 4
5 6 7 8
9 10 11 0
13 14 15 12
Sample Output #1

YES
Sample Input #2

2 1 3 4
5 6 7 8
9 10 11 12
0 13 14 15
Sample Output #2

NO

这个题目是说,输入16个数,0-15,问你这样的状态能不能复原。

详细结论请看我的另外一篇博客。拼图游戏——策略与评定

代码:

#include<iostream>
using namespace std;
 
int list[16];
 
int main()
{	
	int sum = 0;
	for (int i = 0; i < 16; i++)
	{
		cin >> list[i];
		for (int j = 0; j < i; j++)if (list[j]>list[i])sum++;
		if (list[i] == 0)sum += i / 4 + i % 4;
	}
	if (sum % 2)cout << "YES";
	else cout << "NO";
	return 0;
}

三角形问题 FZU - 1881

题目:

给你一个由无穷个节点组成的三角形(如下图),你的任务很简单——任意给你两个正整数x和y,判断它们是否相邻(重合不是相邻)。

Input
第一行T,表示T组测试数据,接下来仅有两个32位正整数x 和y。
Output
对于每组测试数据,首先输出”Case k:”,其中k表示第几组。然后如果x和y相邻,则输出“Yes”,否则输出“No”。
Sample Input
3
1 1
1 2
1 11
Sample Output
Case 1:No
Case 2:Yes
Case 3:No


代码:

#include<iostream>
using namespace std;
 
bool f(int x, int y)
{
	int r = 0;
	for (r = 1; r < x; r++)x -= r, y -= r;
	if (y <= r)return y == x + 1;
	y -= r;
	return (y == x) || (y == x + 1);
}
 
int main()
{
	int n, x, y;
	cin >> n;
	for(int i=1;i<=n;i++)
	{
		cin >> x >> y;
		if (x > y)x ^= y ^= x ^= y;
		cout << "Case " << i << ":";
		if (f(x, y))cout << "Yes\n";
		else cout << "No\n";
	}
	return 0;
}


 

猜你喜欢

转载自blog.csdn.net/nameofcsdn/article/details/114178913