一周的不幸就从做学长的丧题开始
————————————————我是分割线——————————————————
T1:游戏(game)
【问题描述】
小R和小H在玩某个双人联机小游戏,一开始两人所操控的角色各有1点力量值,而在游戏中,每通过一关都会掉落一些力量强化道具。奇怪的是,明明是双人小游戏,每关却都会掉落3个相同的力量强化道具,于是两人决定每关每人先拿一个,剩下一个猜拳决定给谁。一个力量强化道具能使一个角色的力量值变为原来的若干整数倍,同一关卡掉落的道具倍率都相同,而不同的关卡可能不同。小R从攻略上找到了一些会产生特殊效果的力量值组合,他想知道哪些组合是按他们的道具分配方式有可能在通过某关时达成的。
【输入格式】
第一行一个正整数n,表示力量值组合的个数。
接下来n行,每行两个非负整数ai,bi,表示一个力量值组合。
【输出格式】
输出共n行,每行一个”YES”或”NO”表示是否能够达成。
【样例输入】
2
2 4
1 8
【样例输出】
YES
NO
【数据范围】
本题共10个测试点,其中第x个测试点满足n<=max(4^x-1,5),ai,bi<=10^(x-1)。
————————————————我是分割线——————————————————
这道题。。根据题目可知,ai*bi开3次方一定是整数,而且ai%(三次方根)=0,bi%(三次方根)=0
所以直接判断就好了
#include<cstdio> #include<cmath> #define eps 1e-8 using namespace std; int n; long long ans,x,y; double aabs(double a){return a>0?a:-a;} void swap(int &a,int &b){a^=b;b^=a;a^=b;} int main(){ freopen("game.in","r",stdin); freopen("game.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lld%lld",&x,&y); if(x==0&&y==0){puts("YES");continue;} ans=x*y; double qaq=pow(ans,1/3.0); ans=round(qaq); if(aabs(qaq-round(qaq))<eps&&ans!=0&&ans*ans%x==0&&ans*ans%y==0)puts("YES"); else puts("NO"); } fclose(stdin); fclose(stdout); }
————————————————我是分割线——————————————————
T2:数字(number)
【问题描述】
小R被某人要求做一个报告,报告中要用到一些数据,可惜小R没有,只好自己瞎编一个,于是他随便滚了下键盘,出来一个奇怪的数字。因为明眼人都看的出这个数字是乱打的,所以小R打算强化一下这个数字的可信度,首先他把这一大长串数字分成了n个,然后他决定选出其中k个,把它们乘起来得到最后的数字。众所周知,一个数字末尾的0越多越高大上,所以小R想要最大化得到的数字末尾0的数量。按照套路,请你解决一下。
【输入格式】
第一行两个正整数n和k。
接下来n行,每行一个非负整数ai,表示给出的数字。
【输出格式】
输出一个整数,表示答案。
【样例输入】
3 2
20
50
80
【样例输出】
3
【数据范围】
对于20%的数据,n<=15,ai<=10;
对于30%的数据,n<=25;
对于50%的数据,n<=50,ai<=100;
对于70%的数据,n<=100,ai<=10^9;
对于100%的数据,n<=200,ai<=10^18。
————————————————我是分割线——————————————————
DP处理。。。。f[i][j]表示取到第i个,因数中有j个5,因数中最多的2的个数。
贴代码QAQ
#include<cstdio> #include<cstring> #include<algorithm> #define K 25 #define MN 200 using namespace std; int f[MN+5][MN*K+5],s2,s5,ans,n,m; inline void rw(int&a,int b){if(b>a)a=b;} long long x; int main(){ freopen("number.in","r",stdin); freopen("number.out","w",stdout); scanf("%d%d",&n,&m); memset(f,200,sizeof(f));f[0][0]=0; for(int i=1;i<=n;i++){ scanf("%I64d",&x);if(!x){ans=1;continue;} for(s2=0;x%2==0;x/=2,s2++);for(s5=0;x%5==0;x/=5,s5++); for(int j=min(m,i);j--;)for(int k=0;k<=j*K;k++)rw(f[j+1][k+s5],f[j][k]+s2); } for(int i=0;i<=K*m;i++)rw(ans,min(i,f[m][i])); printf("%d ",ans); fclose(stdin); fclose(stdout); }
————————————————我是分割线——————————————————
T3:餐厅(restaurant)
【问题描述】
小R最近在玩一款模拟餐厅打工的游戏,其中有一个叠盘子的小游戏小R很喜欢。这个小游戏是这样的:有一个放盘子的机器会在一条直线上运动,机器里装着n个盘子,其中第i个盘子半径为ri,并且如果要放下该盘子,盘子的中心必须放在直线上xi的位置上,小R可以决定放下哪些盘子和放下这些盘子的顺序,盘子可以放在空位上,或者叠在一个上面没有其他盘子的盘子上,但要求被叠的盘子必须包含要叠上去的盘子。小R想要让叠出的盘子尽量高,请你计算出最高的一叠最多能叠几个盘子。
【输入格式】
第一行一个正整数n,表示盘子数。
接下来n行,每行两个正整数ri和xi。
【输出格式】
输出一个整数,表示答案。
【样例输入】
3
3 5
2 4
2 6
【样例输出】
2
【数据范围】
对于20%的数据,n<=10;
对于50%的数据,n<=1,000;
对于100%的数据,n<=100,000,ri,xi<=10^9。
————————————————我是分割线——————————————————
这道题。。
灰常恶心的QAQ。。。。显然就是求区间最大覆盖咯。
ri,xi这么大,显然离散啊。然后根据套路(划掉),我们按照区间的右端点为第一关键字,区间的长度为第二关键字,进行排序。
然后我们每次用线段树找到目前放的盘子最多的区间(区间完全覆盖当前区间),然后在那个区间上+1,并更新线段树。
#include<cstdio> #include<algorithm> #define maxx(a,b) ((a)>(b)?(a):(b)) #define MN 100005 #define N 131072 using namespace std; struct qq{ int l,r; }a[MN]; int c[MN],t[N<<1],n,cn; bool cmp(qq aa,qq bb){return aa.r<bb.r||(aa.r==bb.r&&aa.l>bb.l);} void renew(int k,int x){for(k+=N;k;k>>=1)t[k]=maxx(t[k],x);} int query(int l,int r){ register int res=0; for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1){ if(~l&1)res=maxx(res,t[l+1]); if(r&1)res=maxx(res,t[r-1]); }return res; } int main(){ freopen("restaurant.in","r",stdin); freopen("restaurant.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%d",&a[i].r,&a[i].l),c[i]=a[i].l-=a[i].r,a[i].r=a[i].l+2*a[i].r; sort(c+1,c+n+1);cn=unique(c+1,c+n+1)-c-1; sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++){ a[i].l=lower_bound(c+1,c+n+1,a[i].l)-c; renew(a[i].l,query(a[i].l,n)+1); } printf("%d ",t[1]); fclose(stdin); fclose(stdout); }
这道题目不是很理解,但是勉强打出来了,改天再详细复习一下。