首页 > 其他 > 详细

【NOIP2016】魔法阵

时间:2018-06-08 15:07:58      阅读:171      评论:0      收藏:0      [点我收藏+]

【Problem description】

 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量。
  大魔法师有m个魔法物品,编号分别为1,2,...,m。每个物品具有一个魔法值,我们用Xi表示编号为i的物品的魔法值。每个魔法值Xi是不超过n的正整数,可能有多个物品的魔法值相同。
  大魔法师认为,当且仅当四个编号为a,b,c,d的魔法物品满足xa<xb<xc<xd,Xb-Xa=2(Xd-Xc),并且xb-xa<(xc-xb)/3时,这四个魔法物品形成了一个魔法阵,他称这四个魔法物品分别为这个魔法阵的A物品,B物品,C物品,D物品。
  现在,大魔法师想要知道,对于每个魔法物品,作为某个魔法阵的A物品出现的次数,作为B物品的次数,作为C物品的次数,和作为D物品的次数。

输入格式

  输入文件的第一行包含两个空格隔开的正整数n和m。
  接下来m行,每行一个正整数,第i+1行的正整数表示Xi,即编号为i的物品的魔法值。
  保证1<=n<=15000,1<=m<=40000,1<=xi<=n。每个Xi是分别在合法范围内等概率随机生成的。

【Input format】

输入文件的第一行包含两个空格隔开的正整数n和m。
接下来m行,每行一个正整数,第i+1行的正整数表示Xi,即编号为i的物品的魔法值。
保证1<=n<=15000,1<=m<=40000,1<=xi<=n。每个Xi是分别在合法范围内等概率随机生成的。

【Output format】

 共输出m行,每行四个整数。第i行的四个整数依次表示编号为i的物品作 为A,B,C,D物品分别出现的次数。
  保证标准输出中的每个数都不会超过10^9。
  每行相邻的两个数之间用恰好一个空格隔开。

【Algorithm design】

 Optimized Enumeration

【Problem analysis】

这题有个很坑的地方:xb-xa<(xc-xb)/3 “/3”是个实数计算

当然可以移到左边化为整型计算

 

然后是思路处理

首先当然是暴力四重枚举

复杂度 O(40000^4)

TLE45

 

发现在枚出abcd任意三者的情况下可以直接求出另一个数字

因为求出的是数值

所以不妨把所有的物品都化成数值

相同数值的只要在hash上累加即可

三重循环复杂度O(40000^3)

TLE85

 

在尝试各种剪枝都无效的情况下

要想新算法

设xd-xc=i,xb-xa=2i,xc-xb>6i

可见i<n/9

再看其实每一组d,c都是可以对应多组a,b存在的

并且在相同i的情况下 在右的d,c是要比左面的对应组数多的

A,b反之

这就可以用前缀和思想来搞

 

核心代码(优化前):

for(int sub_a=1;magic[sub_a]+gap*9<magic[cnt_num];sub_a++)

exist_left[magic[sub_a]+gap*2]=exist_magic[magic[sub_a]]*exist_magic[magic[sub_a]+gap*2];

for(int sub_d=cnt_num;magic[sub_d]-gap*9>magic[1];sub_d--)

exist_right[magic[sub_d]-gap]=exist_magic[magic[sub_d]]*exist_magic[magic[sub_d]-gap];

for(int i=magic[1];i<=magic[cnt_num];i++)

cnt_left[i]=cnt_left[i-1]+exist_left[i];

for(int i=magic[cnt_num];i>=magic[1];i--)

cnt_right[i]=cnt_right[i+1]+exist_right[i];

for(int sub_a=1;magic[sub_a]+gap*9<magic[cnt_num];sub_a++){

cnt[0][magic[sub_a]]+=cnt_right[magic[sub_a]+8*gap+1]*exist_magic[magic[sub_a]+gap*2];

cnt[1][magic[sub_a]+gap*2]+=cnt_right[magic[sub_a]+8*gap+1]*exist_magic[magic[sub_a]];}

for(int sub_d=cnt_num;magic[sub_d]-gap*9>magic[1];sub_d--){

cnt[2][magic[sub_d]-gap]+=cnt_left[magic[sub_d]-7*gap-1]*exist_magic[magic[sub_d]];

cnt[3][magic[sub_d]]+=cnt_left[magic[sub_d]-7*gap-1]*exist_magic[magic[sub_d]-gap];}

 

核心代码(优化后):

for(int gap=1;gap*9<max_mag;gap++)

   {

      int cnt_left[bnd_mag];

      int cnt_right[bnd_mag];

      memset(cnt_left,0,sizeof(cnt_left));

      memset(cnt_right,0,sizeof(cnt_right));

      for(int a=1;a+gap*9<max_mag;a++)

      {

         int b=a+gap*2;

         int least_c=b+gap*6+1;

         cnt_left[least_c]+=cnt_mag[a]*cnt_mag[b];

      }

      for(int c=gap*8+2;c+gap<=max_mag;c++)

      {

         int d=c+gap;

         int least_b=c-gap*6-1;

         cnt_right[least_b]+=cnt_mag[c]*cnt_mag[d];

         cnt_left[c]+=cnt_left[c-1];

         cnt[2][c]+=cnt_left[c]*cnt_mag[d];

         cnt[3][d]+=cnt_left[c]*cnt_mag[c];

      }

      for(int a=max_mag-9*gap-1;a>=1;a--)

      {

         int b=a+gap*2;

         cnt_right[b]+=cnt_right[b+1];

         cnt[1][b]+=cnt_right[b]*cnt_mag[a];

         cnt[0][a]+=cnt_right[b]*cnt_mag[b];

      }

   }

 

 

复杂度O(n^2/9)

【Source code】

TLE45:

#include <bits/stdc++.h>

#define F(i,j,k) for(int i=j;i<=k;i++)

#define D(i,j,k) for(int i=j;i>=k;i--)

#define sc(i) scanf("%d",&i)

#define R return

 

using namespace std;

 

int n,m,x[40001],w[15001],vit[15001],cnt[4][15001],xx[40001];

 

void read()

{

   sc(n);

   sc(m);

   F(i,1,m)

      sc(x[i]);

   R;

}

 

void work()

{

   F(a,1,m)

      F(b,1,m)

      F(c,1,m)

      F(d,1,m)

      if(x[a]<x[b]&&x[b]<x[c]&&x[c]<x[d]&&x[b]-x[a]==2*x[d]-2*x[c]&&3*x[b]-3*x[a]<x[c]-x[b])

      {

         cnt[0][a]++;

         cnt[1][b]++;

         cnt[2][c]++;

         cnt[3][d]++;

      }

   F(i,1,m)

   {

      F(j,0,3)

      cout<<cnt[j][i]<<" ";

      cout<<endl;

   }

   R;

}

 

int main()

{

   freopen("magic.in","r",stdin);

   freopen("magic.out","w",stdout);

   read();

   work();

   R 0;

}

 

TLE 85:

#include <bits/stdc++.h>

#define F(i,j,k) for(int i=j;i<=k;i++)

#define D(i,j,k) for(int i=j;i>=k;i--)

#define sc(i) scanf("%d",&i)

#define R return

 

using namespace std;

 

int n,m,x[40001],w[15001],vit[15001],cnt[4][15001],xx[40001],next[15001];

 

void read()

{

   sc(n);

   sc(m);

   F(i,1,m)

   {

      sc(x[i]);

      vit[x[i]]++;

      xx[i]=x[i];

   }

   sort(x+1,x+m+1);

   F(i,1,m)if(x[i]>x[i-1])

      w[++w[0]]=x[i];

   int sub=1;

   F(i,0,x[m])

   {

      if(w[sub]<i)sub++;

      next[i]=sub;

   }

   R;

}

 

void work()

{

   for(int c=3;c<w[0];c++)

      for(int d=c+1;d<=w[0]&&9*w[d]-9*w[c]<n&&9*w[c]>8*w[d];d++)

      {

         int dis=w[d]-w[c];

         for(int b=next[w[1]+2*dis];b<next[w[c]-6*dis];b++)

         {

            int a=w[b]-2*dis;

            if(vit[a])

            {

               int sum=vit[a]*vit[w[b]]*vit[w[c]]*vit[w[d]];

               cnt[0][a]+=sum/vit[a];

               cnt[1][w[b]]+=sum/vit[w[b]];

               cnt[2][w[c]]+=sum/vit[w[c]];

               cnt[3][w[d]]+=sum/vit[w[d]];

            }

         }

      }

   F(i,1,m)

   {

      F(j,0,3)

         cout<<cnt[j][xx[i]]<<" ";

      cout<<endl;

   }

   R;

}

 

int main()

{

   freopen("magic.in","r",stdin);

   freopen("magic.out","w",stdout);

   read();

   work();

   R 0;

}

 

AC(优化前):

#include <bits/stdc++.h>

#define bound_cnt 40010

#define bound_magic 15010

 

using namespace std;

 

int max_magic,cnt_obj,cnt_num,cnt[4][bound_cnt],magic[bound_cnt],unsort_magic[bound_cnt],waitsort_magic[bound_cnt];

int exist_magic[bound_magic],exist_left[bound_magic],exist_right[bound_magic],cnt_left[bound_magic],cnt_right[bound_magic];;

 

void in()

{

   cin>>max_magic>>cnt_obj;

   for(int i=1;i<=cnt_obj;i++)

   {

      scanf("%d",&unsort_magic[i]);

      waitsort_magic[i]=unsort_magic[i];

      exist_magic[unsort_magic[i]]++;

   }

   sort(waitsort_magic+1,waitsort_magic+cnt_obj+1);

   for(int i=1;i<=cnt_obj;i++)

      if(waitsort_magic[i]>waitsort_magic[i-1])magic[++cnt_num]=waitsort_magic[i];

   return;

}

  

void work()

{

   for(int gap=1;gap*9<magic[cnt_num]-magic[1];gap++)

   {

      memset(exist_left,0,sizeof(exist_left));

      memset(exist_right,0,sizeof(exist_right));

      memset(cnt_left,0,sizeof(cnt_left));

      memset(cnt_right,0,sizeof(cnt_right));

      for(int sub_a=1;magic[sub_a]+gap*9<magic[cnt_num];sub_a++)

         exist_left[magic[sub_a]+gap*2]=exist_magic[magic[sub_a]]*exist_magic[magic[sub_a]+gap*2];

      for(int sub_d=cnt_num;magic[sub_d]-gap*9>magic[1];sub_d--)

         exist_right[magic[sub_d]-gap]=exist_magic[magic[sub_d]]*exist_magic[magic[sub_d]-gap];

      for(int i=magic[1];i<=magic[cnt_num];i++)

         cnt_left[i]=cnt_left[i-1]+exist_left[i];

      for(int i=magic[cnt_num];i>=magic[1];i--)

         cnt_right[i]=cnt_right[i+1]+exist_right[i];

      for(int sub_a=1;magic[sub_a]+gap*9<magic[cnt_num];sub_a++)

      {

         cnt[0][magic[sub_a]]+=cnt_right[magic[sub_a]+8*gap+1]*exist_magic[magic[sub_a]+gap*2];

         cnt[1][magic[sub_a]+gap*2]+=cnt_right[magic[sub_a]+8*gap+1]*exist_magic[magic[sub_a]];

      }

      for(int sub_d=cnt_num;magic[sub_d]-gap*9>magic[1];sub_d--)

      {

         cnt[2][magic[sub_d]-gap]+=cnt_left[magic[sub_d]-7*gap-1]*exist_magic[magic[sub_d]];

         cnt[3][magic[sub_d]]+=cnt_left[magic[sub_d]-7*gap-1]*exist_magic[magic[sub_d]-gap];

      }

   }

   return;

}

 

void out()

{

   for(int i=1;i<=cnt_obj;i++)

   {

      for(int j=0;j<=3;j++)

         cout<<cnt[j][unsort_magic[i]]<<" ";

      cout<<endl;

   }

   return;

}

 

int main()

{

   freopen("magic.in","r",stdin);

   freopen("magic.out","w",stdout);

   in();

   work();

   out();

   return 0;

}

 

AC(优化后):

#include <bits/stdc++.h>

#define bnd_cnt 40010

#define bnd_mag 15010

 

using namespace std;

 

int max_mag,cnt_obj,cnt_num,cnt[4][bnd_mag],mag[bnd_cnt],ust_mag[bnd_cnt],cnt_mag[bnd_mag];

 

void in()

{

   cin>>max_mag>>cnt_obj;

   int wst_mag[bnd_cnt];

   memset(wst_mag,0,sizeof(wst_mag));

   for(int i=1;i<=cnt_obj;i++)

   {

      scanf("%d",&ust_mag[i]);

      wst_mag[i]=ust_mag[i];

      cnt_mag[ust_mag[i]]++;

   }

   sort(wst_mag+1,wst_mag+cnt_obj+1);

   for(int i=1;i<=cnt_obj;i++)

      if(wst_mag[i]>wst_mag[i-1])mag[++cnt_num]=wst_mag[i];

   return;

}

  

void work()

{

   for(int gap=1;gap*9<max_mag;gap++)

   {

      int cnt_left[bnd_mag];

      int cnt_right[bnd_mag];

      memset(cnt_left,0,sizeof(cnt_left));

      memset(cnt_right,0,sizeof(cnt_right));

      for(int a=1;a+gap*9<max_mag;a++)

      {

         int b=a+gap*2;

         int least_c=b+gap*6+1;

         cnt_left[least_c]+=cnt_mag[a]*cnt_mag[b];

      }

      for(int c=gap*8+2;c+gap<=max_mag;c++)

      {

         int d=c+gap;

         int least_b=c-gap*6-1;

         cnt_right[least_b]+=cnt_mag[c]*cnt_mag[d];

         cnt_left[c]+=cnt_left[c-1];

         cnt[2][c]+=cnt_left[c]*cnt_mag[d];

         cnt[3][d]+=cnt_left[c]*cnt_mag[c];

      }

      for(int a=max_mag-9*gap-1;a>=1;a--)

      {

         int b=a+gap*2;

         cnt_right[b]+=cnt_right[b+1];

         cnt[1][b]+=cnt_right[b]*cnt_mag[a];

         cnt[0][a]+=cnt_right[b]*cnt_mag[b];

      }

   }

   return;

}

 

void out()

{

   for(int i=1;i<=cnt_obj;i++)

   {

      for(int j=0;j<=3;j++)

         cout<<cnt[j][ust_mag[i]]<<" ";

      cout<<endl;

   }

   return;

}

 

int main()

{

   freopen("magic.in","r",stdin);

   freopen("magic.out","w",stdout);

   in();

   work();

   out();

   return 0;

}

 

【NOIP2016】魔法阵

原文:https://www.cnblogs.com/qswx/p/9155685.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!