这题算是中难题吧。
如果是暴力统计的方法,复杂度O(n^2),必TLE。
将题目的模型抽象出来,我们要做的就是给你若干个n维的点,确定里面最近的两个点(这里的距离定义为曼哈顿距离),并输出点的标号。
我们先考虑二维的情况。
假定有两个点(x1,y1),(x2,y2)。
则dis=|x1-x2|+|y1-y2|。
考虑将其展开,那么一共有四种情况,分别是:
x1-x2+y1-y2
x1-x2+y2-y1
x2-x1+y1-y2
x2-x1+y2-y1
再考虑将x1与y1放在一起,x2与y2放在一起,那么这四个式子可以变换为:
x1+y1+(-x2-y2)
x1-y1+(-x2+y2)
-x1+y1+x2-y2
-x1-y1+(x2+y2)
再变化一下
x1+y1-(x2+y2)
x1-y1-(x2-y2)
-x1+y1-(-x2+y2)
-x1-y1-(-x2-y2)
而我们注意到,真正的dis一定是对应着这四个式子里面其中的一个的,也是值最大的那个。
那么对于二维的情况,我们可以考虑将每个点枚举4个状态,取每个状态中的最大值和最小值作差,再在四个状态中取最大值即可。
推广到k维的情况,我们只要枚举每个点的2^k个状态,然后执行上述的操作就好了。
最终的复杂度是n*2^k。
如果你拿这个复杂度来写的话,我是TLE了。
我们可以考虑进行折半枚举。
二进制当中有着一定的对应关系,其实我们不需要枚举2^k个状态,这需要枚举2^(k-1)个状态就可以了。
#include "cstdio"
#include "algorithm"
using namespace std;
#define INF 999999
int n,m;
int fp,fa,fm;
int loc[10];
struct node{
int v,no;
}a[1<<7][10005];
void input(){
scanf("%d%d",&n,&m);
scanf("%d%d%d",&fp,&fa,&fm);
for(int i=0;i<n;i++){
scanf("%d",&loc[0]);
loc[1]=loc[0]%fm;
for(int j=2;j<=m;j++){
loc[j]=(loc[j-1]*fp+fa)%fm;
}
for(int s=0;s<1<<(m-1);s++){
a[s][i].v=0;
for(int k=0;k<m;k++){
if((1<<k)&s) a[s][i].v+=loc[k+1];
else a[s][i].v-=loc[k+1];
}
a[(1<<m)-1-s][i].v=-a[s][i].v;
}
}
}
void solve(){
int ans,mx,mn;
int lc1,lc2;
int t1,t2;
ans=-1;
for(int s=0;s<1<<m;s++){
mx=-INF,mn=INF;
for(int i=0;i<n;i++){
if(a[s][i].v>mx) {mx=a[s][i].v;lc2=i;}
if(a[s][i].v<mn) {mn=a[s][i].v;lc1=i;}
}
if(mx-mn>ans){
ans=mx-mn;
t1=lc1,t2=lc2;
}
}
if(t1>t2) swap(t1,t2);
if(t1==t2) t2++;
printf("%d %d %d\n",ans,t1+1,t2+1);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
input();
solve();
}
return 0;
}