题目来自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写的
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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表示白色)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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存直线的两点,之后遍历找平行线。找平行线的话,可以用向量
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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)就是最终所在的窗口编号了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
G题:Rendezvous on a Tetrahedron
把三维展成二维,可以发现有循环节
把最终点的坐标转化到第一个循环节里,再讨论在哪个区域,然后再与输入的边匹配,得到最终的面的编号
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define PI acos(-1.0) 4 struct node 5 { 6 double x,y; 7 }p1,p2; 8 double getpi(double x) 9 { 10 return x*PI/180.0; 11 } 12 double fun(double x) 13 { 14 while(x>2) 15 { 16 x-=2; 17 } 18 return x; 19 } 20 int findArea(node p) 21 { 22 if(p.x+p.y-1<0||(p.x+p.y-3>0&&p.x<2&&p.y<2)) 23 return 1; 24 else if((p.x+p.y-1>0&&p.x<1&&p.y<1)||(p.x+p.y-3<0&&p.x<2&&p.x>1&&p.y<2&&p.y>1)) 25 return 2; 26 else if((p.x+p.y-2<0&&p.x>1&&p.x<2&&p.y<1)||(p.x+p.y-2>0&&p.x<1&&p.y>1&&p.y<2)) 27 return 3; 28 else if((p.x+p.y-2<0&&p.x<1&&p.y>1&&p.y<2)||(p.x+p.y-2>0&&p.x>1&&p.x<2&&p.y<1)) 29 return 4; 30 } 31 int findAns(char ch,int a) 32 { 33 if(ch=='B') 34 { 35 if(a==1) return 1; 36 else if(a==2) return 4; 37 else if(a==3) return 3; 38 else if(a==4) return 2; 39 } 40 else if(ch=='C') 41 { 42 if(a==1) return 2; 43 else if(a==2) return 4; 44 else if(a==3) return 1; 45 else if(a==4) return 3; 46 } 47 else if(ch=='D') 48 { 49 if(a==1) return 3; 50 else if(a==2) return 4; 51 else if(a==3) return 2; 52 else if(a==4) return 1; 53 } 54 } 55 int main() 56 { 57 char op1[3],op2[3]; 58 int d1,l1,d2,l2; 59 scanf("%s%d%d",op1,&d1,&l1); 60 scanf("%s%d%d",op2,&d2,&l2); 61 62 p1.x=l1*sin(getpi(60.0-d1*1.0))/sin(getpi(120.0)); 63 p1.y=l1*sin(getpi(d1*1.0))/sin(getpi(120.0)); 64 65 p2.x=l2*sin(getpi(60.0-d2*1.0))/sin(getpi(120.0)); 66 p2.y=l2*sin(getpi(d2*1.0))/sin(getpi(120.0)); 67 68 p1.x=fun(p1.x); 69 p1.y=fun(p1.y); 70 71 p2.x=fun(p2.x); 72 p2.y=fun(p2.y); 73 74 int a1=findArea(p1); 75 int a2=findArea(p2); 76 77 int ans1=findAns(op1[0],a1); 78 int ans2=findAns(op2[0],a2); 79 80 if(ans1==ans2) printf("YES\n"); 81 else printf("NO\n"); 82 83 return 0; 84 85 }
I题:Starting a Scenic Railroad Service
参考https://blog.csdn.net/xnmzdxws/article/details/80070867
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=2e5; 4 int n,a[N+5],b[N+5],ans1,ans2,r[N+5],sn,sa[N+5],sb[N+5],sc[N+5]; 5 int main() 6 { 7 scanf("%d",&n); 8 for(int i=1;i<=n;i++) 9 { 10 scanf("%d%d",&a[i],&b[i]); 11 sa[a[i]]++; 12 sb[b[i]]++; 13 sc[a[i]]++; 14 sc[b[i]]--; 15 sn=max(sn,b[i]); 16 } 17 for(int i=1;i<=sn;i++) 18 { 19 sa[i]+=sa[i-1]; 20 sb[i]+=sb[i-1]; 21 } 22 for(int i=1;i<=n;i++) 23 ans1=max(ans1,sa[b[i]-1]-sb[a[i]]); 24 for(int i=1;i<=sn;i++) 25 { 26 sc[i]+=sc[i-1]; 27 ans2=max(ans2,sc[i]); 28 } 29 printf("%d %d\n",ans1,ans2); 30 return 0; 31 }