AtCoder Regular Contest 079

C

题意:给出n个点m条边,无向图,问从1走到N是否能在两步之内到达

思路:很显然只有两种情况,第一种情况1和N之间本来就有一条边可以直达,第二种情况1和N之间有个中转点,这个点既可以到1也可以到n,枚举这个点就好

a[]数组记录连接1的点,b[]数组记录连接n的点

#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <utility>
 
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define ft first
#define sd second
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int qq = 2e5 + 10;
const int MOD = 1e9 + 7;
int n, m;
bool a[qq], b[qq];
 
int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; ++i) {
		int x, y;	scanf("%d%d", &x, &y);
		if(x == 1) {
			a[y] = true;
		}
		if(x == n) {
			b[y] = true;
		}
		if(y == 1) {
			a[x] = true;
		}
		if(y == n) {
			b[x] = true;
		}
	}
	if(a[n] == true || b[1] == true) {
		puts("POSSIBLE");
		return 0;
	}
	for(int i = 1; i <= n; ++i) {
		if(a[i] && b[i]) {
			puts("POSSIBLE");
			return 0;
		}
	}
	puts("IMPOSSIBLE");
	return 0;
}


D

题意:先解释一下题目所说的序列吧,这个序列有n个元素,每个元素有一个只ai,每次从这个序列中拿出最大的元素ak,然后进行ak - n,然后除了ak外其他元素全部加1,直到序列中最大的元素小于等于n - 1

题目给你一个k,让你求一个刚好进行k次操作的序列,最后满足序列中最大的元素小于等于n - 1

思路:我们这样来看

比如问规定n = 2,观察下列序列,最后一列表示要进行几次操作之后达到满足条件的序列

1 0    0

2 0    1

2 1    2

3 1    3

3 2    4

4 2    5

..........

可以发现第i行进行一次操作之后状态转化为第i - 1行状态

这个序列的构造很简单,但是n = 2的情况极限数据构造出来ai会超出题目给的ai

所以我们把这个情况推到n = 50, 同理

49 48 47 ... 1 0          0

50 48 47 ... 1 0          1

50 49 47 ... 1 0          2

...

计算也很简单,观察即可发现

#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <utility>
 
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define ft first
#define sd second
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
const int MOD = 1e9 + 7;
LL num[60];
 
int main(){
	LL k;	scanf("%lld", &k);
	int cnt = 0;
	LL tmp = k / 50;
	for(int i = 49; i >= 0; --i) {
		num[cnt] = i;
		num[cnt] += tmp;
		cnt++;
	}
	k = k % 50;
	for(int i = 0; i < 50 && k > 0; ++i, --k) {
		num[i]++;
	}
	printf("50\n");
	for(int i = 0; i < 49; ++i) {
		printf("%lld ", num[i]);
	}
	printf("%lld\n", num[49]);
	return 0;
}



E

题意:是D题的反过程,给出序列a,问经过多少次操作之后达到满足序列,求出k

思路:对于每一个超过n - 1的数而言它肯定是要进行减n操作的,我们可以这样考虑,进行一轮极限操作,就是所有数都降到n一下,然后在统计所得到的序列, 一直得到满足序列为止,正确性- - 我没办法证明。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <utility>
 
using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define ft first
#define sd second
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
const int MOD = 1e9 + 7;
LL num[60];
LL p[qq];
int main(){
	LL n;	scanf("%lld", &n);
	for(int i = 0; i < n; ++i) {
		scanf("%lld", num + i);
	}
	LL k = 0;
	while(1) {
		int cnt = 0;
		for(int i = 0; i < n; ++i) {
			if(num[i] <= n - 1)	cnt++;
		}
		if(cnt >= n)	break;
		LL sum = 0;
		for(int i = 0; i < n; ++i) {
			p[i] = num[i] / n;
			sum += p[i];
		}
		k += sum;
		for(int i = 0; i < n; ++i) {
			num[i] = num[i] - p[i] * n + (sum - p[i]);
		}
	}
	printf("%lld\n", k);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值