2017暑假第二阶段第六场 总结
来源:互联网 发布:ubuntu键盘左alt没反应 编辑:程序博客网 时间:2024/06/06 00:23
T1 2357 数
问题描述
一个数字被称之为 2357 数,当且仅当其所有大于 1 的因子均能被 2/3/5/7 中的某一个整除。对于数字 N,你需要求出不小于 N 的最小 2357 数。
输入格式
一个数字 N。
输出格式
一个数字表示最小的 2357 数
样例输入
209
样例输出
210
数据范围
对于 30%的数据,N≤5000。
对于 60%的数据,N≤10^9。
对于 100%的数据,N≤10^13。
显然,满足条件的数可以表示为
优先队列或单调队列的方法也可以考虑,但实现起来没有循环容易,因为在下面的循环中会在刚得到大于等于N的数的时候就停止,对答案的正确性没有影响。
//代码中的快速幂可以用累乘优化,但是当时懒得写了#include<stdio.h>#define ll long longll N,Ans=(1ll<<60);inline ll _R(){ char s=getchar();ll v=0,sign=0; while((s!='-')&&(s>57||s<48))s=getchar(); if(s=='-')sign=1,s=getchar(); for(;s>47&&s<58;s=getchar())v=v*10+s-48; if(sign)v=-v; return v;}ll ksm(ll a,ll b){ ll ans=1; while(b) { if(b&1)ans=ans*a; b>>=1;a*=a; } return ans;}int main(){ ll i,j,k,l,w,x,y,z; N=_R(); for(i=0;;i++) { w=ksm(2,i); if(w>=N) { if(Ans>w)Ans=w; break; } for(j=0;;j++) { x=w*ksm(3,j); if(x>=N) { if(Ans>x)Ans=x; break; } for(k=0;;k++) { y=x*ksm(5,k); if(y>=N) { if(Ans>y) Ans=y; break; } for(l=0;;l++) { z=y*ksm(7,l); if(z>=N) { if(Ans>z)Ans=z; break; } } } } } printf("%lld",Ans);}
T2 监狱
问题描述
一个监狱,构造很奇特,有N个牢房,但是N个牢房却是一字排起的。也就是说,第i个牢房紧挨着第i+1个(除了末尾那个)。上级要求将某些罪犯释放,给了一份名单,要求每天释放一个人。现在牢房中一共有N个人,他们互相之间可以说话,如果有一个人离开了,那么能和说上话的人就会angry,如果想让他们安静下来,看守必须给angry的人吃肉。
输入格式
第一行两个数N和M,M表示要释放名单上的人数;
第二行M个数,表示释放哪些人
输出格式
仅一行,表示最少要给多少人次送肉吃
样例输入
20 3
3 6 14
样例输出
35
数据范围
对于 30%的数据,1≤N≤100;1≤M≤5。
对于 70%的数据,1≤N≤1000; 1≤M≤100;
对于100%的数据, 1≤N≤4000; 1≤M≤100;
正向考虑要用到费用提前计算的思想,但是不论是从思维上还是代码实现上都比较困难。更简单的方法是反向考虑,依次把需要释放的人“关进监狱”。那么添加一个人,就相当于把这个人两边的区间进行合并,且合并区间需要等于两区间长度和的费用。这就转换成了一道简单的区间DP。状态转移方程:
设f[i][j]表示合并区间[i,j]所需要的最小费用:
f[i][j]=min(f[i][k]+f[k+1][j]+len[i][j])
len[i][j]在代码中体现为sum[i+k]-sum[i-1]-2。
时间复杂度O(M
#include<stdio.h>#include<algorithm>#define Min(x,y) ((x<y)?(x):(y))using namespace std;const int inf=1e9;int N,M,a[123],f[123][123],sum[123];int main(){ int i,j,k; scanf("%d%d",&N,&M); for(i=1;i<=M;i++)scanf("%d",&a[i]); for(i=1;i<=M+1;i++) for(j=1;j<=M+1;j++)f[i][j]=inf; sort(a+1,a+M+1); for(i=1;i<=M+1;i++)f[i][i]=0; for(i=1;i<=M;i++)sum[i]=a[i]-1; sum[1+M]=N; sum[0]=-1; //sum[i]表示第i个人以前的区间总长度,由于这样的意义,注意sum[0]的初值 for(k=1;k<=M;k++) for(i=1;i+k<=M+1;i++) for(j=i;j<i+k;j++) f[i][i+k]=Min(f[i][i+k],((f[i][j]+f[j+1][i+k]+sum[i+k]-sum[i-1]-2))); printf("%d",f[1][M+1]);}
T3 lucknum
问题描述
每个人都会有幸运数字,有种幸运数字是这样定义的:
如果X是幸运数字,则X在m进制下的表示为x1x2…xk,一定有x1<=x2<=…<=xk,其中k可以表示X在m进制下的位数(不能有前导0,除非该数本身就是0)。
这样的数字可能有无穷多个的,但是如果是在m进制下位数不超过n的幸运数字,就应该是有限个了,你能算出来吗?
这个答案可能很大,你只需要输出答案对一个质数p取模的值即可。
输入格式
共一行,三个正整数 n、m 和 p,保证 p 是质数。
输出格式
共一行,表示答案对p取模的值。
样例输入
4 10 10000079
样例输出
715
提示
前 20%的数据满足 n <= 18, m <= 10。
前 50%的数据满足 n <= 100, m <= 100。
前 80%的数据满足 n <= 1000, m <= 1000。
100%的数据满足 n <= 10^7, m <= 10^7, n + m <= p, p <= 10000079
首先容易做出80分算法,思路当然是递推:
设f[i][j]表示讨论到第i位,且最后一位是j的方案总数,那么容易得出递推关系:
1.
f[1][i]=1,0≤i<M
2.f[i][j]=∑jk=0f[i−1][k],i>1,0≤j<M
注意到2式可以用前缀和优化,时间复杂度降到了O(MN),能得80分。
80分代码:
#include<stdio.h>#define ll long longll sum[1005][1005];int N,M;ll P;int main(){ int i,j; scanf("%d%d%lld",&N,&M,&P); for(i=0;i<M;i++)sum[0][i]=1; for(i=1;i<=N;i++) { sum[i][0]=1; for(j=1;j<M;j++)sum[i][j]=(sum[i][j-1]+sum[i-1][j])%P; } printf("%lld",sum[N][M-1]);}
AC算法:
从这里可以看出,sum[i][j]=(sum[i][j-1]+sum[i-1][j])%P。再结合我们所赋的初值,不难想到组合数的递推公式。或者如果用上面的程序打表找规律,也可以发现其实打的表构成了一个斜放的杨辉三角形,然后可以得出答案是
同时,p < m +n 以及p为质数的条件也给了我们一些暗示。
AC代码:
#include<stdio.h>#define ll long longll N,M,P;ll ksm(ll a,ll b){ ll ans=1; while(b) { if(b&1)ans=ans*a%P; b>>=1;a=a*a%P; } return ans;}ll C(ll m,ll n){ if(n>m)return 0; if(n==0)return 1; if(n>m-n)n=m-n; ll i,A=1,B=1; for(i=0;i<n;i++) { A=A*(m-i)%P; B=B*(i+1)%P; } return A*ksm(B,P-2)%P;//P为质数,费马小定理求逆元}int main(){ scanf("%lld%lld%lld",&N,&M,&P); printf("%lld",C(N+M-1,N));}
数学解释(来自PWJ大佬):
对于一个有n位的m进制数,设各位上的数为
观察式子
可以发现上面的问题能转化为隔板法的数学模型:把
总结
T1是道暴力水题;T2只要能想到逆向考虑就变成一道区间DP水题;T3如果用纯数学推导其实并不好想,但是80分算法应该是可以立即弄出来,只要更进一步看出组合数递推公式或想到打表找规律就能轻松AC。
总的来说本次考试比较简单,做完了三道题还对拍了一个多小时,考下来还AK了。
再次意识到随时保存代码的重要性,六号大佬差点就没有AK。只不过二十分钟就打完了三道题的代码并且AK,膜膜膜。
- 2017暑假第二阶段第六场 总结
- 2017暑假第二阶段第一场 总结
- 2017暑假第二阶段第二场 总结
- 2017暑假第二阶段第三场 总结
- 2017暑假第二阶段第四场 总结
- 2017暑假第二阶段第五场 总结
- 2017暑假第二阶段第七场 总结
- 2017暑假第二阶段第八场 总结
- 2017暑假第二阶段第九场 总结
- 暑假第六天总结
- 暑假集训-个人赛第六场
- 大暑假集训 第二阶段
- 第六场训练赛总结
- 2017-11-8离线赛总结 (NOIP七连测第六场)
- linux兴趣小组暑假第六次讲座总结
- 2017暑假集训第六天
- #个人赛第六场解题总结#
- 2010-zzuli暑假集训选拔赛四场总结
- Spark性能优化之数据倾斜技术方案
- 2017.8.27 阿里巴巴算法工程师笔试(2)
- Unity3d
- C++之数组名和指针的区别---补充(10)《Effective C++》
- PopUpWindow使用详解(二)——进阶及答疑
- 2017暑假第二阶段第六场 总结
- Nginx多Server反向代理配置
- 提升方法AdaBoost
- Oracle学习笔记(二) 数据库卸载
- [NOIP模拟赛]虫图
- HNOI 2004 宠物收养所(Splay树)
- cvc-complex-type.2.4.a: Invalid content was found starting with element
- 关于Servlet
- 数组 toString toLocalString valueof 区别