您的位置:首页 > 其它

2016年中国大学生程序设计竞赛(杭州)-重现赛

2016-10-29 17:35 465 查看
虽说天冷打代码冻手,但是退役的时候打一把比赛还是蛮爽的。

感觉今天状态很差,06没考虑负数,最后一题脑残写反判定? 真的要退役了。

A

贪心模拟,不够就一直合并,多的话就一直分解。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
typedef pair<int, int> pii;
LL a[MAXN];
int main()
{
int t, kcase = 1; scanf("%d", &t);
while(t--) {
int n, m; scanf("%d%d", &n, &m);
LL sum = 0;
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
sum += a[i];
}
if(sum % m) {
printf("Case #%d: -1\n", kcase++);
continue;
}
LL ans = 0;
LL aver = sum / m;
int i = 1;
for(int j = 1; j <= m && i <= n; i++) {
while(i <= n && a[i] < aver) {
a[i + 1] += a[i];
i++; ans++;
}
while(a[i] > aver) {
a[i] -= aver; ans++; j++;
}
if(a[i] == aver) {
j++;
}
else {
a[i + 1] += a[i]; ans++;
}
}
printf("Case #%d: %lld\n", kcase++, ans);
}
return 0;
}


B

考虑每个SCC的入度,然后统计贡献。注意特判1的情况的。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e3 + 10;
const int MOD = 1e9 + 7;
const int INF = 1e9 + 7;
typedef pair<int, int> pii;
vector<int> G[MAXN];
vector<int> scc[MAXN];
int x[MAXN], y[MAXN], r[MAXN], c[MAXN];
int low[MAXN], dfn[MAXN];
int dfs_clock;
bool Instack[MAXN];
int scc_cnt;
int sccno[MAXN];
stack<int> S;
void tarjan(int u, int fa) {
int v;
low[u] = dfn[u] = ++dfs_clock;
Instack[u] = true; S.push(u);
for(int i = 0; i < G[u].size(); i++) {
v = G[u][i];
if(!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
}
else if(Instack[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]) {
scc_cnt++;
scc[scc_cnt].clear();
for(;;) {
v = S.top(); S.pop();
sccno[v] = scc_cnt;
scc[scc_cnt].push_back(v);
Instack[v] = false;
if(v == u) break;
}
}
}
void find_cut(int l, int r) {
memset(low, 0, sizeof(low));
memset(dfn, 0, sizeof(dfn));
memset(sccno, 0, sizeof(sccno));
memset(Instack, false, sizeof(Instack));
dfs_clock = scc_cnt = 0;
for(int i = l; i <= r; i++) {
if(!dfn[i]) {
tarjan(i, -1);
}
}
}
int in[MAXN];
int main()
{
int t, kcase = 1; scanf("%d", &t);
while(t--) {
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d%d%d%d", &x[i], &y[i], &r[i], &c[i]);
}
for(int i = 1; i <= n; i++) {
G[i].clear();
for(int j = 1; j <= n; j++) {
if(i == j) continue;
if(1LL * (x[j] - x[i]) * (x[j] - x[i]) + 1LL * (y[j] - y[i]) * (y[j] - y[i]) <= 1LL * r[i] * r[i]) {
G[i].push_back(j);
}
}
}
find_cut(1, n);
for(int i = 1; i <= scc_cnt; i++) in[i] = 0;
for(int i = 1; i <= n; i++) {
for(int j = 0; j < G[i].size(); j++) {
int u = sccno[i];
int v = sccno[G[i][j]];
if(u != v) {
in[v]++;
}
}
}
LL ans = 0;
if(scc_cnt == 1) {
sort(c + 1, c + n + 1);
ans = c[1];
}
else {
for(int i = 1; i <= scc_cnt; i++) {
if(in[i]) continue;
int Min = INF;
for(int j = 0; j < scc[i].size(); j++) {
Min = min(Min, c[scc[i][j]]);
}
ans += Min;
}
}
printf("Case #%d: %lld\n", kcase++, ans);
}
return 0;
}


C

贪心,从后向前模拟。

但是直接用double精度可能会不够,最好的方法就是使用分数的形式。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <stack>
#include <cmath>
#include <iostream>
using namespace std;
typedef unsigned long long LL;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
const int INF = 1e9 + 7;
typedef pair<int, int> pii;
LL a[MAXN];
LL gcd(LL a, LL b) {
return b == 0 ? a : gcd(b, a % b);
}
int main()
{
int t, kcase = 1; scanf("%d", &t);
while(t--) {
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%llu", &a[i]);
}
LL ans = 1; a[0] = 0;
LL v1 = a
- a[n - 1];
LL v2 = 1;
for(int i = n - 1; i >= 1; i--) {
LL d = a[i] - a[i - 1];
if(v1 >= d * v2) {
v1 = d; v2 = 1; ans++;
}
else {
if((d * v2) % v1 == 0) {
ans += d * v2 / v1;
}
else {
LL num = d * v2 / v1 + 1;
v1 = d; v2 = num;
LL GCD = gcd(v1, v2);
v1 /= GCD; v2 /= GCD;
ans += num;
}
}
}
printf("Case #%d: %llu\n", kcase++, ans);
}
return 0;
}


D

首先打个表,发现y<1010。

高效的枚举y,可以将y分两半,类似科学计数法记y=x∗105+y,里面x和y均小于105。预处理前一半,然后统计个数,再枚举后一半,统计贡献。

注意y>0。。。。

代码写的太弱智

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e4 + 10;
const int MOD = 1e9 + 7;
typedef pair<int, int> pii;
LL f[10][10];
LL W(int bit) {
LL ans = 0;
for(int i = 1; i <= bit; i++) {
ans = ans * 10 + 9;
}
return ans;
}
LL sum[100000 + 10][10];
LL rec[100000 + 10], val[100000 + 10];
int num[100000 + 10];
int main()
{
for(int i = 0; i <= 9; i++) {
for(int j = 1; j <= 9; j++) {
f[i][j] = 1;
for(int k = 1; k <= j; k++) {
f[i][j] *= i;
}
}
}
//    for(int i = 6; ; i++) {
//        if(1LL * 1000000000 + W(i) > 1LL * f[9][9] * i) {
//            printf("%d\n", i); break;
//        }
//    } // max(bit) = 10

for(int i = 0; i <= 100000; i++) {
for(int k = 1; k <= 9; k++) {
int n = i;
sum[i][k] = 0;
while(n) {
sum[i][k] += f[n % 10][k];
n /= 10;
}
}
}
int t, kcase = 1; scanf("%d", &t);
while(t--) {
int x, k; scanf("%d%d", &x, &k);

LL ans = 0; int top = 0;
for(int i = 0; i < 100000; i++) {
val[i] = sum[i][k] - 1LL * i * 100000 - x;
rec[top++] = val[i]; num[i] = 0;
}
sort(rec, rec + top); int N = top; top = 1;

for(int i = 1; i < N; i++) {
if(rec[i] != rec[i - 1]) {
rec[top++] = rec[i];
}
}
for(int i = 0; i < 100000; i++) {
num[lower_bound(rec, rec + top, val[i]) - rec]++;
}

for(int i = 0; i < 100000; i++) {
LL V = 1LL * i - sum[i][k];
int p = lower_bound(rec, rec + top, V) - rec;
if(rec[p] == V) {
ans += num[p];
}
}
if(x == 0) {
ans--;
}
printf("Case #%d: %lld\n", kcase++, ans);
}
return 0;
}


F

注意考虑负数的情况,初始化0的活该WA

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
const int INF = 1e9 + 7;
typedef pair<int, int> pii;
char str[100];
int main()
{
int t, kcase = 1; scanf("%d", &t);
while(t--) {
scanf("%s", str); int len = strlen(str);
LL ans = -INF;
for(int i = 0; i < len - 4; i++) {
for(int j = i + 1; j < len - 3; j++) {
LL a = 0;
for(int k = 0; k <= i; k++) {
a = a * 10 + (str[k] - '0');
}
LL b = 0;
for(int k = i + 1; k <= j; k++) {
b = b * 10 + (str[k] - '0');
}

LL c = str[j + 1] - '0';
LL d = str[j + 2] - '0';
LL e = 0;
for(int k = j + 3; k < len; k++) {
e = e * 10 + (str[k] - '0');
}
ans = max(ans, a + b - c * d / e);
}
}
printf("Case #%d: %lld\n", kcase++, ans);
}
return 0;
}


K

存在两个大于n的素数显然是不合法的,而且对于重叠的区间,最优方案是自己和自己匹配,这样就把点数优化到600的规模。跑匹配即可。n和s还可以写反?

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <stack>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
const int INF = 1e9 + 7;
typedef pair<int, int> pii;
vector<int> G[1000];
int match[1000];
bool used[1000];
bool DFS(int u) {
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(!used[v]) {
used[v] = true;
if(match[v] == -1 || DFS(match[v])) {
match[v] = u;
return true;
}
}
}
return false;
}
void Solve(int n) {
memset(match, -1, sizeof(match));
int ans = 0;
for(int i = 1; i <= n; i++) {
memset(used, false, sizeof(used));
ans += DFS(i);
}
printf(ans == n ? "Yes\n" : "No\n");
}
int main()
{
int t, kcase = 1; scanf("%d", &t);
while(t--) {
int n, s; scanf("%d%d", &n, &s);
printf("Case #%d: ", kcase++);
if(s >= n) {
if(n >= 600) {
printf("No\n");
}
else {
for(int i = 1; i <= n; i++) {
G[i].clear();
for(int j = 1; j <= n; j++) {
if((s + j) % i == 0) {
G[i].push_back(j);
}
}
}
Solve(n);
}
}
else {
if(s >= 600) {
printf("No\n");
}
else {
for(int i = 1; i <= s; i++) {
G[i].clear();
for(int j = 1; j <= s; j++) {
if((j + n) % i == 0) {
G[i].push_back(j);
}
}
}
Solve(s);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐