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