您的位置:首页 > 其它

AtCoder Regular Contest 079

2017-07-29 22:16 393 查看
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
== 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: