您的位置:首页 > 其它

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

2016-10-29 18:47 274 查看
做这套重现赛的题目还是很尴尬的,没有现场赛的资格,只能重现赛打一打,过一下瘾了, 还好也A了五道题目,不是很渣。

ArcSoft’s Office Rearrangement

第一题说得不好听点就是一道非常low的题目,直接从开头检测是否满足平分后的条件,如果小于就加,大于就减,尴尬的是比赛的时候没有对−1则会中加Case,结果果断WA,后来发现这个问题,心中是一万个草泥马奔腾而过,真是日了狗了

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;

const int MAXN = 1e5 + 5;

LL A[MAXN];
int N, K;
int main() {
int _;
int cas = 1;
scanf("%d", &_);
while(_ --) {
scanf("%d%d", &N, &K);
LL sum = 0;
for(int i = 1; i <= N; i ++) {
scanf("%I64d", &A[i]);
sum += A[i];
}
LL ys = sum / (LL)K;
if(sum % (LL)K != 0LL) {
printf("Case #%d: -1\n", cas ++);
continue;
}
LL sy = 0;
LL operate = 0;
int l = 1;
while(true) {
if(sy == ys || sy == 0) {
if(l > N) break;
sy = A[l ++];
} else if(sy < ys) {
if(l > N) break;
sy += A[l ++];
operate ++;
} else {
operate ++;
sy -= ys;
}
}
printf("Case #%d: %I64d\n", cas ++, operate);
}
return 0;
}


Bomb

队友xxw做的,这道题目思路还是重要的,就是一个炸弹爆炸会引起在它爆炸区域内的其他炸弹,见一个有向图,将所有入度为0的点全都计算一边贡献然后用Tarjan求一下环内的最小值就可以了

#include <bits/stdc++.h>
using namespace std;

typedef __int64 LL;
typedef pair<LL, LL> PLL;

const int MAXN = 1000 + 5;

int T, cas, N;
struct QNode {
LL x, y, r, c, id;
} q[MAXN];

vector<int> G[MAXN];
set<int> F[MAXN];
set<int>::iterator iter;
int In[MAXN];

int Low[MAXN], DFN[MAXN], Stack[MAXN], Belong[MAXN]; //Belong数组的值是1~scc
int Index, top;
int scc;//强连通分量的个数
bool Instack[MAXN];
int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc
LL w[MAXN];

void Tarjan(int u) {
int v, sz = G[u].size();
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;

for(int i = 0; i < sz; i++) {
v = G[u][i];
if( !DFN[v] ) {
Tarjan(v);
if( Low[u] > Low[v] )Low[u] = Low[v];
} else if(Instack[v] && Low[u] > DFN[v])
Low[u] = DFN[v];
}
if(Low[u] == DFN[u]) {
scc++;
do {
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
} while( v != u);
}
}

void fuck() {
memset(DFN, 0, sizeof(DFN));
memset(Instack, false, sizeof(Instack));
memset(num, 0, sizeof(num));
Index = scc = top = 0;
for(int i = 1; i <= N; i++)
if(!DFN[i])
Tarjan(i);
memset(w, 0x3f, sizeof(w));
for(int i = 0; i <= scc; i++) F[i].clear();

for(int u = 1; u <= N; u++) {
int x = Belong[u], y, v, sz = G[u].size();;
w[x] = min(w[x], q[u].c);
for(int j = 0; j < sz; j++) {
v = G[u][j], y = Belong[v];
if(x == y) continue;
F[x].insert(y);
In[y] ++;
}
}
}

bool IsInter(QNode& a, QNode& b) {
LL dist = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
return dist <= a.r * a.r;
}

int main() {
scanf("%d", &T); cas = 0;
while(T --) {
scanf("%d", &N);
for(int i = 1; i <= N; i++) {
scanf("%I64d %I64d %I64d %I64d", &q[i].x, &q[i].y, &q[i].r, &q[i].c);
}
memset(In, 0, sizeof(In));
for(int i = 1; i <= N; i++) {
G[i].clear();
for(int j = 1; j <= N; j++) {
if (j == i) continue;
if(IsInter(q[i], q[j])) {
G[i].push_back(j);
}
}
}
fuck();
LL ans = 0;
for(int i = 1; i <= scc; i++) {
if(In[i] == 0) {
ans += w[i];
}
}
printf("Case #%d: %I64d\n", ++cas, ans);
}
return 0;
}


Car

题意非常简单,就是让一辆车从0开始开,速度不能减少,然后求到达最后一个点的最小时间,倒过来处理就可以了,打重现赛的时候这里WA了几发,后面hl队友对除数部分加了个eps就过了,尴尬!

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp          make_pair
#define pb          push_back
#define FIN         freopen("in.txt", "r", stdin)
#define FOUT        freopen("out.txt", "w", stdout)
#define lson        l, mid, cur << 1
#define rson        mid + 1, r, cur << 1 | 1
#define debug       puts("-------------");
#define lowbit(x)   ((x)&(-(x)))
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-5;
const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 50;
const int MAXM = 1e4 + 50;

int n;
LL num[MAXN];

int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
int T;
scanf("%d", &T);
for (int _ = 1; _ <= T; _++) {
scanf("%d", &n);
num[0] = 0;
for (int i = 1; i <= n; i++)
scanf("%I64d", &num[i]);
LL ans = 0;
double last = 1e15;
for (int i = n - 1; i >= 0; i--) {
double len = num[i + 1] - num[i];
LL k = (LL)(ceil(len / last) + eps);
ans += k;
last = (len + eps) / k;
}
printf("Case #%d: %I64d\n", _, ans);
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}


Four Operations

这道题目意思很简单,直接暴力枚举,当然全部暴力是不行的,为此队友英勇的WA了几发,然后改变策略,枚举加减,乘除部分就非常好处理了,当然是分子越小,分母越大最小,然后就A了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>

using namespace std;
typedef long long LL;

const int MAXN = 2e2 + 5;
const LL INF = 1e18;

char S[MAXN];

LL calcA(char buf[], int l, int r) {
LL a = 0, b = 0, ans = 0;
for(int i = l; i < r - 1; i ++) {
a = 0, b = 0;
for(int j = l; j <= i; j ++) {
a = a * 10 + buf[j] - '0';
}
for(int j = i + 1;j < r;j ++){
b = b * 10 + buf[j] - '0';
}
ans = max(ans, a + b);
}

return ans;
}

LL calcB(char buf[], int l, int r) {
LL a = 0, b = 0, c = 0;
a = buf[l] - '0';
b = buf[l + 1] - '0';
for(int i = l + 2; i < r; i ++) {
c = c * 10LL + buf[i] - '0';
}
c = a * b / c;
return c;
}

int main() {
int _;
int cas = 1;
scanf("%d", &_);
while(_ --) {
scanf("%s", S);
int len = strlen(S);
LL Maxs = -INF;
for(int i = 2; i <= len - 3; i ++) {
LL a = calcA(S, 0, i);
LL b = calcB(S, i, len);
Maxs = max(Maxs, a - b);
}
printf("Case #%d: %I64d\n", cas ++,  Maxs);
}
return 0;
}


Kingdom of Obsession

一看题目n,s数据大小吓死人,最开始直接猜想题目意思是一个区间内如果有两个素数以上的话就是NO, 否则就是YES,果断WA, 没办法,这么大的数据只能试着找规律了,老老实实构图,写二分图匹配,很英明的发现status(n,s)=status(s,n),因为s是不影响时间复杂度的,所有我们在处理的时候发现n>s就swap(n,s),让n尽可能小,然后看打表的结果发现n>12以后就为NO了,果断判断,然而WA了,接着我们试着将n写成1000,咦,竟然A了,好尴尬呀,A的莫名其妙

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp          make_pair
#define pb          push_back
#define FIN         freopen("in.txt", "r", stdin)
#define FOUT        freopen("out.txt", "w", stdout)
#define lson        l, mid, cur << 1
#define rson        mid + 1, r, cur << 1 | 1
#define debug       puts("-------------");
#define lowbit(x)   ((x)&(-(x)))
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-5;
const int MOD = 1e9 + 7;
const int MAXN = 1e4 + 50;
const int MAXM = 1e4 + 50;

struct Edge{
int v, nxt;
}E[MAXN];
int tot, Head[MAXN];
void edge_init() {
tot = 0;
memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v) {
E[tot].v = v;
E[tot].nxt = Head[u];
Head[u] = tot++;
}

int match[MAXN];
bool check[MAXN];
bool DFS(int u) {
for(int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(!check[v]) {
check[v] = 1;
if(match[v] == -1 || DFS(match[v])) {
match[v] = u;
return 1;
}
}
}
return 0;
}
int Hungray(int n) {
int res = 0;
memset(match, -1, sizeof(match));
for(int u = 1; u <= n; u++) {
memset(check, 0, sizeof(check));
if(DFS(u)) res++;
}
return res;
}

int main() {
#ifdef LOCAL_NORTH
//    FIN;
#endif // LOCAL_NORTH
int T, s, n;
scanf("%d", &T);
for (int _ = 1; _ <= T; _++) {
scanf("%d%d", &s, &n);
if (n > s) swap(s, n);
printf("Case #%d: ", _);
if (n > 1000) {
printf("No\n");
continue;
}
edge_init();
for (int i = s + 1; i <= s + n; i++) {
for (int j = 1; j <= n ;j++) {
if (i % j == 0) {
edge_add(i - s, j);
}
}
}
printf("%s\n", Hungray(n) == n ? "Yes" : "No");
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}


总结一下:

做题目的时候还是先以最简单的方式解决问题,然后再试着用优化算法去处理,铜牌区毕竟不会涉及到太多算法,有足够多的脑洞,够暴力,嗯,思维从简到繁,一步一步的来。

唉,实力基本在铜牌区,太渣了,咋办,估计青岛区域赛得打铁
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐