NOIP 2014 模拟赛 普及组

Problem 1. 小 X 的加法难题

Input file: sum.in
Output file: sum.out
Time limit: 1 second
Memory limit: 256 MB


题目描述:
第一节编程课上,老师要求大家写一个程序计算两个正整数的和。
看到小 X 不屑的眼神后,老师决定给小 X 增加难度。以求 12 和 3 的和为例,老师在 12 + 3 这个
原始式子里加入一些无用的空格,再把它交给小 X。
这下小 X 傻眼了,希望你帮帮他。
Input
第一行包含一个字符串,表示老师给小 X 的式子。
Output
若式子的结果不超过 108,则第一行包含一个整数,表示式子的结果;否则第一行包含一个字符串“Large”。

Example
sum.in

1 2 + 3
sum.out
15

Scoring
• 对于 30% 的数据,式子中不包含无用的空格,式子的结果不超过 108。 • 对于 100% 的数据,字符串长度不超过 100。

思路:
这其实求是一道大模拟题,我们只需注意下‘+’的位置,
然后分别将‘+’前后的字符串转为数字出入a,b两个变量。
然后,题目可能会有一百位的字符串输入,所以我们
需要注意一下‘+’前后组成数字后的位数,大于8位就输出
“Large”了。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#define ll long long
using namespace std;
const ll MAX=1e8;
string s;
ll a, b, i, al, bl;
int main()
{
    
    
	freopen("sum.in", "r", stdin);
	freopen("sum.out", "w", stdout);
	getline(cin, s);
	ll len=s.size();
	for(i=0; i<len; i++)
	{
    
    
		if(al>8) {
    
    printf("Large\n"); return 0;}
		if(s[i] >= '0' && s[i] <= '9') a=a * 10 + (s[i] - '0'), ++al;
		if(s[i] == '+') break;
		//printf("i=%d a=%d\n", i, a);
	}
	for(ll j=i; j<len; j++)
	{
    
    
		if(bl>8) {
    
    printf("Large\n"); return 0;}
		if(s[j] >= '0' && s[j] <= '9') b=b * 10 + (s[j] - '0'), ++bl;
	}
	//cout<<a<<' '<<b<<endl;
	if(a + b > MAX
	) printf("Large\n");
	else printf("%lld", a + b);
	return 0;
} 

Problem 2. 小 X 的密码破译

Input file: password.in
Output file: password.out
Time limit: 1 second
Memory limit: 256 MB


题目描述:
这天小 Y 有事外出,小 X 又忘记带电脑了,于是想使用小 Y 的电脑。不幸的是,小 Y 设了密码,
密码提示是四个整数,且输错后密码和提示就会重新生成。正当小 X 一筹莫展的时候,他打开小 Y 的抽屉,发现里面有一张小纸条,上面写着:“给出提示n, a, b, c,令 di = (a i 2 i^2 i2 + bi + c) m o d mod mod 11111111(1 ≤ i ≤ n),将序列 d 去除重复的数后从小到大排序得到序列 e,设序列 e 有 m 个数,则密码为 ( ∑ i = 1 m i e i \sum_{i=1}^{m} ie_i i=1miei) m o d mod mod 11111111。”
小 X 十分激动,想立刻完成密码破译,希望你帮帮他。

Input
第一行包含四个整数 n, a, b, c。
Output
第一行包含一个整数,表示密码。

Example
password.in

3 0 0 2

password.out

2

Scoring

扫描二维码关注公众号,回复: 12048143 查看本文章

• 对于 30% 的数据,n ≤ 103。 • 对于 60% 的数据,n ≤ 105。 • 对于 100% 的数据,1 ≤ n ≤ 107,0 ≤ a, b, c ≤ 100。

思路:
根据题意模拟即可

#include <cstdio>
#include <iostream>
using namespace std;
const int MAXN = 11111111;
int n, a, b, c, ans;
bool v[MAXN];
int main() {
    
    
    freopen("password.in", "r", stdin);
    freopen("password.out", "w", stdout);
    scanf("%d%d%d%d", &n, &a, &b, &c);
    for (int i = 1; i <= n; ++i)
        v[(a * 1ll * i * i + b * 1ll * i + c * 1ll) % MAXN] = true;
    for (int i = 0, m = 0; i < MAXN; ++i)
        if (v[i]) ans = (ans + (++m) * 1ll * i) % MAXN;
    printf("%d", ans);
    return 0;
}

Problem 3. 小 X 的液体混合

Input file: mixture.in
Output file: mixture.out
Time limit: 1 second
Memory limit: 256 MB


题目描述:
虽然小 X 不喜欢化学原理,但他特别喜欢把一大堆液体倒在一起。
现在小 X 有 n 种液体,其中 m 对会发生反应。现在他想把这 n 种液体按某种顺序倒入一个容器
内,让他获得最刺激的体验,也就是使危险系数尽量大。
我们可以这样计算危险系数,一开始容器内没有任何液体,危险系数为 1。每次液体倒入容器时,
若容器内已有一种或多种液体会与这种液体发生反应,则危险系数会乘 2,否则危险系数不变。
最大危险系数小 X 不会算,希望你帮帮他。
Input
第一行包含两个整数 n, m。
接下来 m 行,每行包含两个整数 a, b,表示液体 a 和液体 b 会发生反应。
Output
第一行包含一个整数,表示最大危险系数。
Example
mixture.in

3 2
1 2
2 3

mixture.out

4

Scoring
• 对于 30% 的数据,n ≤ 10。
• 对于 100% 的数据,1 ≤ n ≤ 1000,a = b,同种反应不会出现多次。

思路:
我们把题目分成多个集合,或是说连通块。设有x个,那么它能贡献的最大价值为 2 n − x 2^{n-x} 2nx

解释一下,我们先来看对于某一个连通块,如下图:
在这里插入图片描述
图有点特别,不要在意!!
那它的最大贡献肯定是: 2 m − 1 2^{m-1} 2m1 (m表示当前这个连通块有m个节点)

根据题意,那按贪心来算,我们肯定是每次选这个块中度最大的作为根节点,
然后再将与它相连的点为根节点,重复当前操作。这个大家应该都理解,
所以最后一定是在这个连通块中的每一个点(除根节点外)都是可以
直接或间接与根节点发生化学反应的。
那它的最大价值不就是 2 m − 1 2^{m-1} 2m1,减一是指根节点,因为第一次加入的液体
是没有一个与它发生化学反应的。

接着我们再回到一个大图中,那最大价值是不是就是每一个
连通块的价值和,即:Ans=2 m 1 − 1 ^{m_1-1} m11+2 m 2 − 1 ^{m_2-1} m21+2 m 2 − 1 ^{m_2-1} m21…+2 m x − 1 ^{m_x-1} mx1
那有x个连通块,是不是就是减去x个一,那x个连通块的内部节点个数,
不就是这个图的总结点个数(x的意思看上文),so…最后答案就为 2 n − x 2^{n-x} 2nx

#include <iostream>
#include <cstdio>
using namespace std;
const int N=1e3+10;
int n, m, u, v, fa[N], tot, ans[N];
int find(int x) {
    
    return x == fa[x]? x : fa[x] = find(fa[x]);}
void unionn(int u, int v)
{
    
    
	int x = find(u), y = find(v);
	fa[x]=y;
}
void gjc()
{
    
    
	int x=0, temp;
	for(int i = N; i >= 1 ; i--)
	{
    
    
		temp = ans[i] * 2 + x;
		x = temp / 10;
		ans[i] = temp % 10;
	}
}
int main()
{
    
    
	freopen("mixture.in", "r", stdin);
	freopen("mixture.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) fa[i] = i; 
	for(int i = 1; i <= m; i++)
		scanf("%d%d", &u, &v), unionn(u, v);
	for(int i = 1; i <= n; i++)
		if(fa[i] == i) tot++;
	//printf("%d\n", tot);
	ans[N] = 1;
	for(int i = 1; i <= n - tot; i++) gjc(); 
	int j = 1;
	while(!ans[j]) j++;
	for(int i = j; i <= N; i++) printf("%d", ans[i]);
	return 0;
} 

Problem 4. 小 X 的AK计划


题目描述:
在小X的家乡,有机房一条街,街上有很多机房。每个机房里都有一万个人在切题。小X刚刷完CodeChef,准备出来逛逛。

机房一条街有 n 个机房,第 i 个机房的坐标为 xi ,小X的家坐标为 0。小X在街上移动的速度为1,即从 x1 到 x2 所耗费的时间为 |x1 − x2|。 每个机房的学生数量不同,ACM 题目水平也良莠不齐。小X到达第 i 个机房后,可以花 ti 的时间想题,然后瞬间 AK;当然,也可以过机房而不入。

小X现在只有 m 个单位时间,之后他就该赶着去打 Codeforces 了。现在他想知道自己最多能在多少个机房 AK,希望你帮帮他。

Input:
第一行包含两个整数 n,m。
接下来 n 行,每行包含两个整数 x i x_i xi t i t_i ti

Output:
第一行包含一个整数,表示小X最多能 AK 的机房数量。

Example
.in

2 10
1 100
5 5

.out

1

Scoring
对于 30% 的数据, n ≤ 20 n ≤ 20 n20
对于 60% 的数据, n ≤ 1000 n ≤ 1000 n1000
对于 100% 的数据, 1 ≤ n ≤ 1 0 5 , 0 ≤ m , x i ≤ 1 0 18 , 0 ≤ t i ≤ 1 0 9 1 ≤ n ≤ 10^5,0 ≤ m,x_i ≤ 10^{18},0 ≤ t_i ≤ 10^9 1n1050mxi10180ti109

ps: 大佬们都用什么大根堆,小根堆的,但我只会贪心。

思路:
首先将每一机房的路程和AK时间汇总,记作tot,
再根据tot将每一机房的information做升序排序;
接着,我们再看题,
从 x1 到 x2 所耗费的时间为 |x1 − x2|
也就是说,刷完一家机房,
到另一家机房所用的时间应为:
|这家机房的位置-下一家机房的位置|
在这里可以简化为“下一家的位置-这家的位置”,因为机房在街上的位置一定是正的
那怎么得知当前机房是从哪里来的,
我设了一个变量last,来记住上一个机房的位置,
并在到达另一家机房时更新。
最后我们判断一下已用的tine超过m,输出答案,
但是比赛时,就是因为这个,害我失去了20分,
最后还需特判一下所有机房都AK后的用时还小于m的情况。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define ll long long

using namespace std;

const int MAX=2147483647;
const int N=1e5+10;
struct AK
{
    
    
	ll road, ak_time, tot;
} data[N];
ll n, m, used_time, ans, last;
bool cmp(AK a, AK b) {
    
    return a.tot < b.tot;}
int main()
{
    
    
	//fre();
	scanf("%lld%lld", &n, &m);
	for(ll i = 1; i <= n; i++)
	{
    
    
		scanf("%lld%lld", &data[i].road, &data[i].ak_time);
		data[i].tot = data[i].ak_time + data[i].road;
		//输入数据的汇总
	}
	sort(data + 1, data + 1 + n, cmp);
	for(ll i = 1; i <= n; i++)
	{
    
    
		if(used_time + data[i].tot - last > m)
			{
    
    printf("%lld\n", ans); return 0;}
		used_time += data[i].tot - last;
		last = data[i].road;
		ans++;
	}
	printf("%lld\n", ans); //特判
	return 0;
}

猜你喜欢

转载自blog.csdn.net/bigwinner888/article/details/109128338