【NOIP2016】提高组
Day1
T1玩具谜题
简单模拟题,注意一下取余啊方向啊什么的就行了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 const int M=1e5+10; 5 using namespace std; 6 struct point{ 7 int fa; 8 char ch[12]; 9 }e[M]; 10 int main() 11 { 12 int n,m,tu,k,now=0; 13 scanf("%d %d",&n,&m); 14 for(int i=0;i<=n-1;i++) 15 scanf("%d %s",&e[i].fa,e[i].ch); 16 for(int i=1;i<=m;i++){ 17 scanf("%d %d",&tu,&k); 18 if((!e[now].fa&&!tu)||(e[now].fa&&tu))now=(now-k+n)%n; 19 else now=(now+k)%n; 20 } 21 printf("%s",e[now].ch); 22 return 0; 23 }
T2天天爱跑步
神题,当然得写独立的题解-->戳这里
T3换教室
期望dp,也有独立题解-->戳这里
Day2
T1组合数问题
预处理杨辉三角(顺便取模),再用另一个三角s[x][y]表示0 <= i <= n, 0 <= j <= min(i, m)里C(i,j)为0的数量-->类似前缀和。
然后就可以O(1)查询啦!
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 int t,k,n,m,c[2002][2002],s[2002][2002]; 7 int read() 8 { 9 int ans=0,f=1;char c=getchar(); 10 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 11 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 12 return ans*f; 13 } 14 int main() 15 { 16 t=read();k=read(); 17 c[0][0]=1; 18 for(int i=1;i<=2000;i++) 19 { 20 c[i][0]=1; 21 for(int j=1;j<=i;j++) 22 { 23 c[i][j]=(c[i-1][j-1]+c[i-1][j])%k; 24 } 25 } 26 s[0][0]=0; 27 for(int i=1;i<=2000;i++) 28 { 29 s[i][0]=0; 30 for(int j=1;j<i;j++) 31 { 32 s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]; 33 if(c[i][j]==0)s[i][j]++; 34 } 35 s[i][i]=s[i][i-1];if(!c[i][i])s[i][i]++; 36 } 37 for(int i=1;i<=t;i++) 38 { 39 scanf("%d %d",&n,&m); 40 printf("%d\n",s[n][min(n,m)]); 41 } 42 return 0; 43 }
T2蚯蚓
这道题用STL的优先队列只能拿65分......
仔细想想会发现,每次截出的两条蚯蚓,如果我们把较大的和较小的分别放进两个队列里,就会发现满足递减性质!
这样就省去了排序->v->
每次从原队列和另外两个队列里取出最长的一条执行操作就好了。
但要注意精度的问题-->不要像我一样自作聪明地把u提前变成v-u-->这样会有±1的误差。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef double Cu; 5 const int N=1e5+10,M=7e6+10; 6 int read(){ 7 int ans=0,f=1;char c=getchar(); 8 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 9 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 10 return ans*f; 11 } 12 int max(int x,int y){return x>y?x:y;} 13 int min(int x,int y){return x<y?x:y;} 14 int n,m,q,u,v,t,a[N],mul[3][M]; 15 int q1[M],q2[M],ans[M]; 16 int h1=1,t1=0,h2=1,t2=0,h=1; 17 void get_rank(){ 18 int rank=1,sum=0; 19 while(rank<=n+m&&sum<(n+m)/t){ 20 bool kk=rank%t; 21 int mx=h<=n?a[h]+mul[0][h]:0,mx1=h1<=t1?q1[h1]+mul[1][h1]:0,mx2=h2<=t2?q2[h2]+mul[2][h2]:0; 22 mx=max(mx,max(mx1,mx2)); 23 if(!kk)printf("%d ",mx),sum++; 24 if(h<=n&&mx==a[h]+mul[0][h])mul[0][h+1]+=mul[0][h],h++; 25 else if(h1<=t1&&mx==mx1)mul[1][h1+1]+=mul[1][h1],h1++; 26 else mul[2][h2+1]+=mul[2][h2],h2++; 27 rank++; 28 } 29 } 30 bool cmp(int x,int y){return x>y;} 31 int get_p(int x){ 32 return (long long)x*u*1.0/v; 33 } 34 int main(){ 35 n=read();m=read();q=read();u=read();v=read();t=read(); 36 Cu p=u*1.0/v; 37 for(int i=1;i<=n;i++)a[i]=read(); 38 std::sort(a+1,a+1+n,cmp); 39 for(int i=1;i<=m;i++){ 40 int mx=h<=n?a[h]+mul[0][h]:0,mx1=h1<=t1?q1[h1]+mul[1][h1]:0,mx2=h2<=t2?q2[h2]+mul[2][h2]:0; 41 mx=max(mx,max(mx1,mx2)); 42 ans[i]=mx; 43 if(h<=n&&mx==a[h]+mul[0][h])mul[0][h+1]+=mul[0][h],h++; 44 else if(h1<=t1&&mx==mx1)mul[1][h1+1]+=mul[1][h1],h1++; 45 else mul[2][h2+1]+=mul[2][h2],h2++; 46 if(h<=n)mul[0][h]+=q; 47 mul[1][h1]+=q;mul[1][++t1]-=q; 48 mul[2][h2]+=q;mul[2][++t2]-=q; 49 int small=get_p(mx);int big=mx-small; 50 if(small>big)std::swap(small,big); 51 q1[t1]=big; 52 q2[t2]=small; 53 } 54 for(int i=1;i<=m/t;i++)printf("%d ",ans[i*t]); 55 printf("\n"); 56 get_rank(); 57 return 0; 58 }
T3愤怒的小鸟
可以剪枝DFS,当然这个数据范围很明显就是状压DP。
g[i][j]表示选择了i,j这两个点作为一条抛物线可以经过的猪的状态-->01状态;
那么预处理就是O(n3)的。状态转移方程:
f[s|g[i][j]]=min(f[s|g[i][j]],f[s]+1);
其中s为当前状态,这样的话总复杂度是O(n3+n2*2n)。
最后就是注意一下判断三点是否在一条抛物线上的精度问题和抛物线必须满足a<0
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mem(a,p) memset(a,p,sizeof(a)) 5 typedef double Cu; 6 const Cu eps=1e-10; 7 Cu xi[20],yi[20]; 8 int f[1<<19],g[20][20]; 9 int min(int x,int y){return x<y?x:y;} 10 Cu abs(Cu x){return x>0?x:-x;} 11 int main(){ 12 int tt,n,m; 13 scanf("%d",&tt); 14 while(tt--){ 15 scanf("%d %d",&n,&m); 16 int mx=(1<<n)-1;f[0]=0; 17 for(int i=1;i<=mx;i++)f[i]=25; 18 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)g[i][j]=0; 19 for(int i=1;i<=n;i++)scanf("%lf %lf",&xi[i],&yi[i]),f[1<<(i-1)]=1; 20 for(int i=1;i<=n;i++) 21 for(int j=i;j<=n;j++) 22 if(i==j)g[i][i]=1<<(i-1); 23 else{ 24 if(xi[i]==xi[j]||abs(xi[j]*yi[i]-yi[j]*xi[i])<eps)continue; 25 Cu a=(xi[j]*yi[i]-xi[i]*yi[j])/(xi[i]*xi[j]*(xi[i]-xi[j])); 26 Cu b=(yi[i]-xi[i]*xi[i]*a)/xi[i]; 27 if(a>=0)continue; 28 int now=(1<<(i-1))+(1<<(j-1)); 29 g[i][j]=now; 30 for(int k=1;k<=n;k++){ 31 if(k==i||k==j)continue; 32 if(abs(a*xi[k]*xi[k]+b*xi[k]-yi[k])<=eps)g[i][j]|=1<<(k-1); 33 } 34 } 35 for(int s=0;s<=mx;s++){ 36 for(int i=1;i<=n;i++) 37 for(int j=i;j<=n;j++) 38 f[s|g[i][j]]=min(f[s|g[i][j]],f[s]+1); 39 } 40 printf("%d\n",f[mx]); 41 } 42 return 0; 43 }
NOIP提高组系列就终于完结辣(撒花~~)
希望还能有机会补今年的题=)