UPC2018组队训练赛第七场

Posted scott527407973

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UPC2018组队训练赛第七场相关的知识,希望对你有一定的参考价值。

题目来自ICPC 2017 Japan Tsukuba

 


 

A题:Secret of Chocolate Poles

有三种巧克力,分别是厚度为1的白色巧克力,厚度为1或者k的黑色巧克力。要求把巧克力放到高度为 l 的盒子里,并且要黑白相间,底部和顶部必须都是黑色的

当l=1,ans=1;当l<k,ans=(l-1)/2+1;当l=k,ans=(l-1)/2+2;当l>k时,就可以转化成排列组合问题了,枚举厚度为k的黑色巧克力数目i,然后对于每一种情况,再枚举厚度为1的黑色巧克力的数目j,那么此时排列的情况就是(i+j)! / ( i! * j! )。最后取和就行了。

因为阶乘会爆longlong,所以就用java写的

技术分享图片
 1 import java.util.*;
 2 import java.math.BigInteger;
 3 public class Main {
 4  
 5     public static void main(String[] args) {
 6         // TODO Auto-generated method stub
 7         Scanner cin = new Scanner(System.in);
 8         BigInteger[]fac=new BigInteger[60];
 9         fac[0]=BigInteger.valueOf(1);
10         BigInteger tmp;
11         for(int i=1;i<60;i++) {
12             tmp=BigInteger.valueOf(i);
13             fac[i]=fac[i-1].multiply(tmp);
14         }
15         int l,k;
16         l= cin.nextInt();
17         k=cin.nextInt();
18         int flag=0;
19         long aa=0;
20         BigInteger ans=BigInteger.valueOf(0);
21         if(l==1)    aa=1;
22         else if(l<k) aa=(l-1)/2+1;
23         else if(l==k)   aa=(l-1)/2+2;
24         else
25         {
26             flag=1;
27             BigInteger tt,pp;
28             for(int i=0;i*(k+1)<=(l-1);i++)
29             {
30                 for(int j=0;j*2<=(l-1-i*(k+1));j++)
31                 {
32                     tt=fac[i].multiply(fac[j]);
33                     pp=fac[i+j].divide(tt);
34                     ans=ans.add(pp);
35                 }
36             }
37             for(int i=0;i*2<=(l-k);i++)
38             {
39                 for(int j=0;j*(k+1)<=(l-k-i*2);j++){
40                     tt=fac[i].multiply(fac[j]);
41                     pp=fac[i+j].divide(tt);
42                     ans=ans.add(pp);
43                 }
44             }
45         }
46         if(flag==1)
47             System.out.println(ans);
48         else
49         {
50             ans=BigInteger.valueOf(aa);
51             System.out.println(ans);
52         }
53              
54     }
55  
56 }
View Code

之后看了大佬的代码https://www.cnblogs.com/clrs97/p/8537178.html  发现可以用dp

f[i][j]代表高度为i,顶层颜色为j的方案数。(j=0,表示黑色,j=1表示白色)

技术分享图片
 1 #include<cstdio>
 2 typedef __int128 lll;
 3 const int N=200;
 4 lll f[N][2],ans;//dark white
 5 int l,k,i;
 6 void write(lll x){
 7     if(x>=10)write(x/10);
 8     x%=10;
 9     printf("%d",(int)(x));
10 }
11 int main(){
12     scanf("%d%d",&l,&k);
13     f[1][0]++;
14     f[k][0]++;
15     for(i=1;i<=l;i++){
16         f[i+1][1]+=f[i][0];
17         f[i+1][0]+=f[i][1];
18         f[i+k][0]+=f[i][1];
19     }
20     for(i=1;i<=l;i++)ans+=f[i][0];
21     write(ans);
22 }
View Code

 

B题:Parallel lines

给偶数个点,两点形成直线,保证任意三点不在同一条直线,问最多能找到多少对平行线

写个搜索,找到所有的直线的可能情况,然后用vector存直线的两点,之后遍历找平行线。找平行线的话,可以用向量

技术分享图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 struct node
 5 {
 6     int x,y;
 7 } Point[20];
 8 int n,ans=-1;
 9 bool vis[20];
10 vector<pair<int,int> >line;
11 void countt()
12 {
13     int tmp=0;
14     for(int i=0; i<line.size(); i++)
15     {
16         int x1=Point[line[i].first].x-Point[line[i].second].x;
17         int y1=Point[line[i].first].y-Point[line[i].second].y;
18         for(int j=i+1; j<line.size(); j++)
19         {
20             int x2=Point[line[j].first].x-Point[line[j].second].x;
21             int y2=Point[line[j].first].y-Point[line[j].second].y;
22             if(x1*y2==x2*y1)
23             {
24                 tmp++;
25             }
26         }
27     }
28     ans=max(ans,tmp);
29 }
30 void dfs(int now)
31 {
32     if(now==n+1)
33     {
34         countt();
35         return;
36     }
37     if(vis[now])
38     {
39         dfs(now+1);
40     }
41     else
42     {
43         for(int i=1; i<=n; i++)
44         {
45             if(vis[i]||i==now)
46             {
47                 continue;
48             }
49             line.push_back(make_pair(now,i));
50             vis[now]=vis[i]=1;
51             dfs(now+1);
52             line.pop_back();
53             vis[now]=vis[i]=0;
54         }
55     }
56 }
57 int main()
58 {
59     scanf("%d",&n);
60     for(int i=1; i<=n; i++)
61     {
62         scanf("%d %d",&Point[i].x,&Point[i].y);
63     }
64     dfs(1);
65     printf("%d
",ans);
66     return 0;
67 }
68  
View Code

 

C题:Medical Checkup

有很多个窗口,有n个人,每个人去窗口办理业务的时间不同,问在t分钟时,每个人分别在哪个窗口

首先求一下每个人在第一个窗口待的时间,然后遍历每个人,如果t小于当前这个人在第一个窗口待的时间,直接输出1;否则,我们可以发现每个人在其他的窗口待的时间是相同的,如果当前这个人办理业务需要的时间小于他前一个人的,那么他在以后的每一个窗口所带的时间就是h[i]=h[i]+h[i-1]-h[i]=h[i-1],不小于的话就直接是他自己办理业务的时间h[i],对于每一个人,用 tt=t-sum[i] 表示这个人离开第一个窗口后还剩的时间,用 tt/h[i]+1,代表在tt这段时间里他能往后走多少个窗口,最后再加上第一个窗口(tt/h[i]+2)就是最终所在的窗口编号了。

技术分享图片
 1  
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=100050;
 5 int n;
 6 ll h[N],sum[N],t;
 7 int main()
 8 {
 9     scanf("%d %lld",&n,&t);
10     for(int i=1;i<=n;i++)
11     {
12         scanf("%lld",&h[i]);
13         sum[i]=sum[i-1]+h[i];
14     }
15     for(int i=1;i<=n;i++)
16     {
17         ll tt=t-sum[i];
18         if(tt<0)
19         {
20             printf("1
");
21             continue;
22         }
23         else
24         {
25             if(h[i]<h[i-1])
26             {
27                 h[i]+=(h[i-1]-h[i]);
28             }
29             ll ans=tt/h[i];
30             ans+=2;
31             printf("%lld
",ans);
32         }
33     }
34     return 0;
35 }
View Code

 

以上是关于UPC2018组队训练赛第七场的主要内容,如果未能解决你的问题,请参考以下文章

Contest1814 - 2019年我能变强组队训练赛第七场

UPC2018组队训练赛第九场

UPC2018组队训练赛第三场

备战省赛组队训练赛第十六场(UPC)

2021年度训练联盟热身训练赛第七场 K题预处理加二分

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&#39;s problem(manacher+二分/枚举)