2016年中国大学生程序设计竞赛(杭州)解题报告

还没做完,ACM的题目真多,一场考试有11道。MD我只有一个人。

A题(HDU5933)

  分析:容易发现最左边的只能从它右边得到,容易想到一个贪心过程,只需要没到规定大小就合并,到了就分裂,不难证明这是最优的。

  代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 template<typename T>
 5 void in(T &x){
 6     char ch = getchar();x=0;
 7     while(ch>'9'||ch<'0') ch = getchar();
 8     while(ch <= '9' && ch >= '0') x = x*10+ch-'0',ch = getchar();
 9 }
10 ll a[120000];
11 
12 int main(){
13     int t; in(t);
14     for(int ti = 1; ti <= t; ti++) {
15     ll n,k; in(n),in(k);
16     ll sum = 0;
17     for(int i = 1; i <= n; i++){
18         in(a[i]);
19         sum = sum + a[i];
20     }
21     printf("Case #%d: ",ti);
22     ll ans = 0;
23     if(sum % k != 0){printf("-1\n");}
24     else{
25         ll last = a[1];
26         for(int i = 2; i <= n;){
27         if(last == sum/k){last = a[i]; i++;continue;}
28         if(last < sum/k){last += a[i]; ans ++;i++;}
29         else{last -= (sum/k);ans++;}
30         }
31         ans += last/(sum/k)-1;
32         printf("%I64d\n",ans);
33     }
34     }
35     return 0;
36 }
View Code

B题(HDU5934)

  分析:将图画出来容易建模成一张图。不难发现只需要缩点后将入度为0的点全部选起来就可以了。

  代码:

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int x[1200],y[1200],r[1200],c[1200],num;
 4 int arr[1200],scc[1200],dfn[1200],low[1200];
 5 int minn[1200],cl;
 6 vector <int> g[1200];
 7 void tarjan(int);
 8 const double eps = 1e-6;
 9 
10 int main(){
11     int t;
12     scanf("%d",&t);
13     for(int o = 1 ;o <= t ; o++){
14     int n;
15     scanf("%d",&n);
16     for(int i=1;i<=n;i++) g[i].clear();
17     for(int i=1;i<=n;i++){
18         scanf("%d%d%d%d",&x[i],&y[i],&r[i],&c[i]);
19     }
20     for(int i=1;i<=n;i++){
21         for(int j=1;j<=n;j++){
22         if(i == j) continue;
23         double dist = sqrt(pow(x[j]-x[i],2)+ pow(y[j]-y[i],2));
24         if((double)r[i]-dist>=-eps){
25             g[i].push_back(j);
26         }
27         }
28     }
29     memset(arr,0,sizeof(arr));
30     memset(dfn,0,sizeof(dfn));
31     memset(low,0,sizeof(low));
32     memset(scc,0,sizeof(scc));
33     cl = 0,num = 0;
34     memset(minn,127/3,sizeof(minn));
35     for(int i=1;i<=n;i++){
36         if(arr[i]) continue;
37         tarjan(i);
38     }
39     memset(arr,0,sizeof(arr));
40     for(int i=1;i<=n;i++){
41         for(int j=0;j<g[i].size();j++){
42         if(scc[g[i][j]]==scc[i])continue;
43         arr[scc[g[i][j]]] = 1;
44         }
45     }
46     int ans = 0;
47     for(int i=1;i<=num;i++)
48         if(!arr[i])
49         ans+=minn[i];
50     printf("Case #%d: %d\n",o,ans);
51     }
52     return 0;
53 }
54 
55 stack <int> sta;
56 void tarjan(int now){
57     low[now] = dfn[now] = ++cl;
58     sta.push(now);
59     for(int i=0;i<g[now].size();i++){
60     int k = g[now][i];
61     if(arr[k]) continue;
62     if(dfn[k]){
63         low[now] = min(low[now],dfn[k]);
64     }else{
65         tarjan(k);
66         low[now] = min(low[now],low[k]);
67     }
68     }
69     if(low[now] == dfn[now]){
70     num++;
71     while(!sta.empty()){
72         int k = sta.top();
73         sta.pop();
74         scc[k] = num;
75         arr[k] = 1;
76         minn[num] = min(minn[num],c[k]);
77         if(k == now)break;
78     }
79     }
80 }
View Code

 

C题(HDU5935)

  分析:容易想到一种贪心策略。只需要从后往前在尽量短的时间内跑完这一段。那么可以用二分法。

  代码:

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[120000];
 4 double v;
 5 int last,now;
 6 long long divide(long long l,long long r){
 7     if(l == r) return l;
 8     long long mid = (l+r) >> 1;
 9     if((double)(last-now)/(double)mid <=v){
10     return divide(l,mid);
11     }else
12     return divide(mid+1,r);
13 }
14 
15 int main(){
16     int t,ti = 1; scanf("%d",&t);
17     while(t--){
18     memset(a,0,sizeof(a));
19     int n; scanf("%d",&n);
20     for(int i=1;i<=n;i++)
21         scanf("%d",&a[i]);
22     v = a[n]-a[n-1];
23     long long ans = 1;
24     for(int i=n-2;i>=0;i--){
25         last = a[i+1];now = a[i];
26         long long k = divide(1,LONG_LONG_MAX/2);
27         ans += k;
28         v = (double)(last-a[i])/(double)k;
29     }
30     printf("Case #%d: %I64d\n",ti,ans);//I64d
31     ti++;
32     }
33 }
View Code

 

D题以后待填

 

转载于:https://www.cnblogs.com/1-1-1-1/p/6759274.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值