2016年中国大学生程序设计竞赛 CCPC (杭州)
A - ArcSoft's Office Rearrangement HDU - 5933
题意:
给你n个数,你有两个操作:1.将相邻两个数合并 2.将一个数拆分成两个数
求将这n个数变成k个相同的数最小操作数。
思路
实际上要变为k个相同的数,每次的合并和分解都是必要的,那么可以直接先合并后分解。
#include <bits/stdc++.h>
//#pragma GCC optimize(3) //如果有STL,开O3
#define endl '\n'
#define pii pair<int,int>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int t, n, k, a[N], cnt, sum,ans= 0, ave,tt, tot;
void solve(){
cin >> t;
while(t -- ){
tt ++;
cin >> n >> k;
ans = 0;
cnt = 0;
for(int i = 1; i <= n; i++){
cin >> a[i];
ans += a[i];
}
sum = 0;
if(ans % k == 0){
ave = ans / k;
for(int i = 1; i <= n; i++){
sum += a[i];
if(sum % ave == 0){
cnt += tot + (sum / ave - 1);
tot = 0;
sum = 0;
}
else{
tot ++;
}
}
cout <<"Case #"<<tt<<": " <<cnt << endl;
}
else{
cout <<"Case #"<<tt<<": " <<-1 << endl;
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
B - Bomb HDU - 5934 强连通分量tarjan
题意:
给出n个炸弹的坐标(x,y)、爆炸能辐射成一个圆的半径r和引爆该炸弹需要的代价c,
且某一个炸弹爆炸后,无需要代价直接引爆在能辐射圆内的炸弹,
问如何引爆所有炸弹需要的最小代价。
思路:
做题先是想到了dp,后来又想到了并查集,后来发现都解决不了。A可以引爆B但是,B不一定引爆A的问题。
后来想到了强连通分量:
- 将可以相互引爆的进行缩点;
(因为无论选择谁都可以连环炸) - 然后对缩后的点建立有向边;
建立的图一定是棵树(或者是森林) - 然后只需要选择所有树的根节点即可。
因为是有向边,选择其他的点也需要再选择根节点,但是选择就可以连环炸掉他的所有子树。
代码:
错误代码(超时了)
超时原因:
写了一个check函数,因为check的参数是Node,
调用时会很慢.....具体也不清楚队友说的。 下次注意了。- 初始化时用的memset(x,0,sizeof x),每次会初始化整个数组
- 使用了函数pow
void init(){
}
struct Node
{
int x,y;
int r,val;
}a[N];
bool check(Node q,Node p){
int len=pow(abs(q.x-p.x),2)+pow(abs(q.y-p.y),2);
if(len>(q.r*q.r)) return false;
else return true;
}
void tarjan(int u){
}
int xxx;
void slove(){
}
signed main()
{
}
正确代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define int long long
const int N = 1010;
const int M = 2e6 + 10;
int n;
int to[M], pre[M], h[N], idx;
int dfn[N], low[N], temp;
int id[N], scc_cnt, scc_size[N], scc_min[N];
int stk[N], top;
bool in_stk[N];
int d[N];
void init()
{
for (int i = 0; i <= n; i++)
h[i] = -1;
for (int i = 0; i <= n; i++)
scc_min[i] = 0x3f3f3f3f3f;
for (int i = 0; i <= n; i++)
in_stk[i] = false;
for (int i = 0; i <= n; i++)
d[i] = 0;
for (int i = 0; i <= n; i++)
dfn[i] = 0;
for (int i = 0; i <= n; i++)
low[i] = 0;
top = 0;
idx = 0;
scc_cnt = 0;
temp = 0;
}
struct Node
{
int x, y;
int r, val;
} a[N];
void add(int x, int y)
{
to[idx] = y, pre[idx] = h[x], h[x] = idx++;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++temp;
stk[++top] = u;
in_stk[u] = true;
for (int i = h[u]; i != -1; i = pre[i])
{
int j = to[i];
if (!dfn[j])
{
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if (in_stk[j])
low[u] = min(low[u], dfn[j]);
}
if (low[u] == dfn[u])
{
int y;
scc_cnt++;
do
{
y = stk[top--];
in_stk[y] = false;
id[y] = scc_cnt;
scc_size[scc_cnt]++;
scc_min[scc_cnt] = min(a[y].val, scc_min[scc_cnt]);
} while (y != u);
}
}
bool check(int i, int j)
{
int len = (a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y);
if (len > (a[i].r * a[i].r))
return false;
else
return true;
}
int xxx;
void slove()
{
cin >> n;
init();
for (int i = 0; i < n; i++)
{
cin >> a[i].x >> a[i].y >> a[i].r >> a[i].val;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (i == j)
continue;
if (check(i, j))
add(i, j);
}
}
for (int i = 0; i < n; i++)
{
if (!dfn[i])
tarjan(i);
}
for (int i = 0; i < n; i++)
{
for (int j = h[i]; j != -1; j = pre[j])
{
int y = to[j];
if (id[i] != id[y])
d[id[y]]++;
}
}
int cnt = 0;
for (int i = 1; i <= scc_cnt; i++)
{
if (!d[i])
{
cnt += scc_min[i];
}
}
printf("Case #%lld: %lld\n", ++xxx, cnt);
}
signed main()
{
int t;
cin >> t;
while (t--)
{
slove();
}
return 0;
}
C - Car HDU - 5935
题意:
车子从起始位置 0开始到达终点一共有 N 个位置被标记,每个位置被标记的时间都是整数时间,并且车子只能做加速运动和匀速运动。问,车子最短时间达到终点的时间花费。
思路:
逆向贪心模拟,最好一段肯定是一秒花费,根据这个速度来往前推,速度不严格递减,保证每段时间是整数。看代码吧
因为速度是小数,为了避免精度丢失,采用分数形式来表示。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define int long long
const int N = 1e5+10;
const int M = 2e6 + 10;
int n;
int a[N];
int case_=1;
void slove()
{
scanf("%lld", &n);
a[0]=0;
for(int i=1;i<=n;i++){
scanf("%lld", &a[i]);
}
int ans=1;
int p=a[n]-a[n-1],q=1;
for(int i=n-1;i>=1;i--){
int dis=a[i]-a[i-1];
q*=dis;
swap(p,q);
int t=ceil(1.0*p/q);
ans+=t;
p=dis,q=t;
}
printf("Case #%lld: %lld\n", case_++, ans);
}
signed main()
{
int t;
scanf("%lld", &t);
while (t--)
slove();
return 0;
}
# F - Four Operations HDU - 5938
题意:
给你一个只有“1~9”数字的字符串,求按顺序插入“+”,“-”,“*”,“/”后,算式能够得到的最大值。
思路 贪心,看代码吧
#include <bits/stdc++.h>
//#pragma GCC optimize(3) //如果有STL,开O3
#define endl '\n'
#define pii pair<int,int>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int t, ans, tt;
int max(int a, int b){
if(a > b) return a;
else return b;
}
void solve(){
cin >> t;
while(t -- ){
string st;
// st = "0";
tt ++;
cin >> st;
if(st.size() == 5){
cout <<"Case #"<<tt<<": ";
cout << (st[0] -'0') + ( st[1] -'0') - (st[2] - '0') * (st[3] - '0') / (st[4] - '0') << endl;
}
else{
int len = st.size() - 1;
//last
int s4 = st[len] - '0';
int s3 = st[len - 1] - '0';
int s2 = st[len - 2] - '0';
int s1 = 0;
if(len - 3 >= 2){
int u = st[0] - '0';
int v = 0;
for(int i = 1; i <= len - 3; i ++){
v = v * 10 + (st[i] - '0');
}
// cout << u <<" - " << v << endl;
s1 = u + v;
//cout <<"?" << s1 << endl;
u = st[len - 3] - '0';
v = 0;
for(int i = 0; i <= len - 4; i ++){
v = v * 10 + (st[i] - '0');
}
s1 = max(s1, u + v);
ans = s1 - s2 * s3 / s4;
// cout <<s1 <<" "<<s2 <<" " << s3 <<" "<<s4 <<endl;
// cout << 1 <<" " << ans << endl;
}
else{
s1 = st[0] -'0' + (st[1] - '0');
ans = s1 - s2 * s3 / s4;
//cout << 1 <<" " << ans << endl;
}
//last1
s4 = (st[len - 1] - '0') * 10 + (st[len] - '0');
s3 = st[len - 2] -'0';
s2 = st[len - 3] - '0';
if(len - 4 >= 2){
int u = st[0] - '0';
int v = 0;
for(int i = 1; i <= len - 4; i ++){
v = v * 10 + (st[i] - '0');
}
s1 = u + v;
u = st[len - 4] - '0';
v = 0;
for(int i = 0; i <= len - 5; i ++){
v = v * 10 + (st[i] - '0');
}
s1 = max(s1, u + v);
ans = max(ans, s1 - s2 * s3 / s4);
//cout << 2 <<" " << ans << endl;
}
else{
s1 = st[0] -'0' + (st[1] - '0');
ans = max(ans,s1 - s2 * s3 / s4);
//cout << 2 <<" " << ans << endl;
}
cout <<"Case #"<<tt<<": " << ans << endl;
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}