题目来自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 }
之后看了大佬的代码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 }
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\n",ans); 66 return 0; 67 } 68
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\n"); 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\n",ans); 32 } 33 } 34 return 0; 35 }
UPC2018组队训练赛第七场
原文地址:https://www.cnblogs.com/scott527407973/p/9556301.html