1. 程式人生 > >【NOIP2016】魔法陣

【NOIP2016】魔法陣

ace DC abc algorithm 計算 前綴 -m d+ 左面

【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】魔法陣