【NOIP2016】魔法阵(节选自冬雪_狂舞_桀骜-xmy的博客)

来源:互联网 发布:网络机房应急预案 编辑:程序博客网 时间:2024/05/17 04:16

 现在来找找AC方式,首先,剖析题目,列出条件:Xa<Xb<Xc<Xd,Xb-Xa=2(Xd-Xc),Xb-Xa<Xc-Xb/3

        遇到这种有条件的题,通常把图形画出来比较直观。


        如图所示,若把d点确定,设c-d距离为i,则a,b的距离就是2i,则b,c的距离>2*(a-b)也就是>6i,总距离大于9i,那么我们的外层循环就枚举i,再枚举d的位置,d的方案数就等于(前面所有a的方案)*(前面所有b的方案)*(当前c的方案数),c的方案数=(前面所有a的方案)*(前面所有b的方案)*(当前d的方案数),同理,枚举a的位置,也可以得到a与b的方案数。     

        当然,说了这么多估计你也可能是懵逼的,看看代码再结合一下分析吧。

[cpp] view plain copy
 print?
  1. #include<cstdio>  
  2. #define M 15005  
  3. int a[M],b[M],c[M],d[M],w[3*M],h[3*M];  
  4. int n,m,i,j,x,s;//s就是上面的y,累加和  
  5. int main()  
  6. {  
  7.     scanf("%d%d",&n,&m);  
  8.     for(i=1;i<=m;i++)  
  9.     {  
  10.         scanf("%d",&h[i]);  
  11.         w[h[i]]++;  
  12.     }  
  13.     for(i=1;9*i<n;i++)//注意是总长度>9*i,边界一定要考虑无误,想通为什么  
  14.     {  
  15.         x=9*i+1;s=0;//设边界最好画个草图自己算一算  
  16.         for(j=9*i+2;j<=n;j++)  
  17.         {  
  18.             s+=w[j-x]*w[j-x+2*i];  
  19.             d[j]+=s*w[j-i];  
  20.             c[j-i]+=s*w[j];  
  21.         }  
  22.         s=0;  
  23.         for(j=n-x;j>=1;j--)//注意循环不能顺序,因为s的累加和会改变,a[j]会加上后面的c,d,而不是前面的  
  24.         {  
  25.             s+=w[j+x]*w[j+x-i];  
  26.             a[j]+=s*w[j+2*i];  
  27.             b[j+2*i]+=s*w[j];  
  28.         }  
  29.     }  
  30.     for(i=1;i<=m;i++)  
  31.         printf("%d %d %d %d\n",a[h[i]],b[h[i]],c[h[i]],d[h[i]]);  
  32. }  

0 0