NOIP2016提高组Day2
来源:互联网 发布:手机淘宝详情制作软件 编辑:程序博客网 时间:2024/06/11 11:24
一、组合数问题
数据:
数据也没有用……因为所有询问中k的值是一样的,直接预处理组合数。处理时一直模k,这样求出来的就是这个数模k的余数。等于0的就是k的倍数。然后前缀和一下就行了。
二、蚯蚓
数据:
当m==0时就是排从大到小排序输出
前60分按照题目模拟,在加上优先级队列或者手打堆就能过了。基本上就是每次弹出最大值,然后拆分,再放回去。
但是显然log n 太慢了,能不能快一点?注意到拆分的时候,每次拆的都是最大的,那么拆掉的数放到原序列里不一定有序,但是如果重新开两个数组存放,一个放拆掉后大的,一个放小的,那么肯定这两个数组肯定是有序的了。为什么?先放的数是由较大的数拆分而得,显然大。那么就可以在常数时间内把最大的找到,可以从三个地方:原序列、拆分后较大的、拆分后较小的,然后拆完后继续放进去就行了。输出使只要不断询问下一个最大值,知道没有时返回一个-1,判断一下就行了。
还有一点,因为拆的时候是不会增长的,所以放进去的时候要进行一番处理
#include<bits/stdc++.h>#define M 100005#define N 7000005#define ll long longusing namespace std;int n,m,zt,t,U,V;int n1,n2,n3,m1,m2,m3;ll A1[M+N],A2[M+N],A3[M+N];//三个数组:原序列,切完后较大的、较小的bool cmp(int x,int y){return x>y;}//原序列先排序ll Find(int x){ int k1=A1[m1]+zt*x,k2=A2[m2]+zt*x,k3=A3[m3]+zt*x; //分别是此时三个序列里最大的数 if(m1>n1)k1=-1;if(m2>n2)k2=-1;if(m3>n3)k3=-1;//如果没了赋值为-1 if(k1>=k2&&k1>=k3){m1++;return k1;} if(k2>=k1&&k2>=k3){m2++;return k2;} if(k3>=k1&&k3>=k2){m3++;return k3;} return -1;}int main(){ scanf("%d%d%d%d%d%d",&n,&m,&zt,&U,&V,&t); for(int i=1;i<=n;i++)scanf("%lld",&A1[i]); sort(A1+1,A1+1+n,cmp); n1=n;n2=n3=0;m1=m2=m3=1;//ni为边界,mi为此时用到第几个数 for(int i=1;i<=m;i++){ ll x=Find(i-1);//找最大值 if(i%t==0)printf("%lld ",x); ll a1=1.0*x*U/V,a2=x-a1;//拆分 if(a1>a2){A2[++n2]=a1-zt*i;A3[++n3]=a2-zt*i;}//此时减去现在的增长量,上面再加总增长量,这样就抵消了 else{A2[++n2]=a2-zt*i;A3[++n3]=a1-zt*i;}//分开来放 } puts(""); ll x=Find(m);int cnt=1; while(x!=-1){//不断弹出最大值 if(cnt%t==0)printf("%lld ",x); x=Find(m); cnt++; } puts(""); return 0;}
三、愤怒的小鸟
数据:
这道题分成两块:一块是判断两个点是否在一个抛物线上;另一个是状压dp。
判断抛物线我的方法很麻烦,先用手写的方法一点点算出中间变量,最后把算出方程式y=a * x^2+b * x 中的a和b(x、y是已知的),由因为还有一个点是(0,0),所以最后有判定了一遍是否符合。最后把a、b记录下来,这样抛物线就存下来了,为了后面预处理判定用。
因为不同抛物线射到的个数不同,所以要预处理那些可以社到的抛物线。已经有一个点(0,0),再枚举两个点就能确定一个抛物线,再一遍循环把剩下的点在这条抛物线上的点取出来,这样预处理就好了。
最后是状压dp了。这个想到应该不难,因为n的范围小于等于18,而且又是多个里选几个,那么就是状压dp了。转移也很简单,看代码
#include<bits/stdc++.h>using namespace std;struct node{double x,y;}A[20];struct node1{double a,b;};int B[405],dp[1<<19];node1 f(int x,int y){//根据手推的方法计算y=a*x^2+b*x中的a和b,并且返回a、b double y1=A[x].y,y2=A[y].y; double k1=A[x].x*A[x].x,k2=A[y].x*A[y].x; double b1=A[x].x,b2=A[y].x; double s1=k1/k2,s2=b1/b2; double b=(y1-y2*s1)/(b1-b2*s1); double a=(y1-y2*s2)/(k1-k2*s2); return (node1){a,b};}bool Judge(node1 a,int x,int y){//判定在两点是不是在此抛物线上 if(a.a>=0)return 0; if(abs(a.a*A[x].x*A[x].x+a.b*A[x].x-A[x].y)<1e-6&&abs(a.a*A[y].x*A[y].x+a.b*A[y].x-A[y].y)<1e-6)return 1; return 0;}int main(){ memset(dp,63,sizeof dp); int cas; scanf("%d",&cas); while(cas--){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%lf%lf",&A[i].x,&A[i].y); int n1=0; for(int i=1;i<=n;i++){//枚举两个点 for(int j=i+1;j<=n;j++){ node1 a1=f(i,j); if(!Judge(a1,i,j))continue;//如果这两个点在抛物线上才往下 int h=(1<<(i-1))+(1<<(j-1)); for(int k=j+1;k<=n;k++)if(Judge(a1,i,k))h+=(1<<(k-1));//把后面的在抛物线上的移进去 B[++n1]=h; } B[++n1]=1<<(i-1); } dp[0]=0; for(int i=0;i<(1<<n);i++){ for(int j=1;j<=n1;j++) if((i&B[j])==B[j])continue;//现在方案包含B[i]方案 else dp[i|B[j]]=min(dp[i|B[j]],dp[i]+1);//能多打就转移 if(i!=(1<<n)-1)dp[i]=1e9;//多组数据为后面的清无限大 } printf("%d\n",dp[(1<<n)-1]); dp[(1<<n)-1]=1e9; } return 0;}
可悲的我考试时三道题,前两道对了,第三道判断的地方精度不够,只开了1e-4,改1e-6就对了。而且第一题还暴零了,因为数组越界了,当cnt[0][0] 时还访问了cnt[i-1][j] 等,这样就到-1了。但是只超了一位来着,网站上都对的……大佬说测评机数组越界时地址很神奇……以后越界要小心了。
- NOIP2016提高组Day2
- 【NOIP2016提高组day2】蚯蚓
- NOIP2016提高组day2 蚯蚓
- 【NOIP2016提高组day2】愤怒的小鸟
- NOIP2016提高组day2 天天爱跑步
- NOIP2016提高组day2 愤怒的小鸟
- 蚯蚓 NOIP2016 提高组 Day2 T2
- NOIP2016提高组复赛day2 组合数问题
- 【NOIP2016提高组复赛day2】天天爱跑步
- NOIP2016 提高组Day2 T1 组合数问题
- {小结}NOIP2016提高A组模拟8.19(雅礼联考day2)
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)树上路径
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)公约数
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)总结
- CCF全国信息学奥林匹克联赛(NOIP2016)复赛模拟提高组 day2 解题报告
- C++ & Pascal & Java ——NOIP2016提高组day2 t1——组合数问题
- C++——NOIP2016提高组day2 t2——蚯蚓
- C++ & Pascal——NOIP2016提高组day2 t3——愤怒的小鸟
- C#中问号“?”的用法
- 2017.10.30一试
- 关于url,src,href的区别联系
- php将文件转化为baseb4位编码形式(方案一)
- Java-String类
- NOIP2016提高组Day2
- Linux安装JDK
- Word Embedding 和Skip-Gram模型 的实践
- Request header is too large
- eclipse上的项目部署之后丢失css,js等配置文件,只有lib文件
- java基础之常用类—File类和String类(重点)
- Git日常命令使用
- 将jmeter返回的json数据转码
- php将文件转化为baseb4位编码形式(方案二)