(題目描述略)
設魔法值爲 j 物品 numj 個,則魔法陣 xa,xb,xc,xd 對於 A, B, C, D 物品貢獻分別爲 numxb∗numxc∗numxd,numxa∗numxc∗numxd,numxa∗numxb∗numxd,numxa∗numxb∗numxc。設 i=xd−xc,則 xb−xa=2i,xc−xb>6i,xd−xb>7i,xc−xa>8i,xd−xa>9i。枚舉 i∈[1,⌊9n−1⌋],並枚舉 xa,xd 使得 1≤xa≤xd≤n 且 xd−xa>9i,由 xb=xa+2i 和 xc=xd−i 得出每組可能 xa,xb,xc,xd 統計即可,這樣可得 85 分。
對於滿分算法,考慮當 xa=n−9i−1,即 xb=n−7i−1 時,相應 {xc=n−ixd=n;當 {xa=n−9i−2xb=n−7i−2 時,相應 {xc=n−ixd=n 或 {xc=n−1−ixd=n−1。一般的,當 {xa=n−9i−jxb=n−7i−j(1≤j<n−9i) 時,相應 xc,xd 解集爲 {xa=n−9i−j+1xb=n−7i−j+1 解集和 {xc=n−j+1−ixd=n−j+1 的並集,對於 A, B 物品貢獻分別爲 numxb∗∑k=1j(numn−k+1−i∗numn−k+1) 和 numxa∗∑k=1j(numn−k+1−i∗numn−k+1),而 ∑k=1j(numn−k+1−i∗numn−k+1)=∑k=1j−1(numn−k+1−i∗numn−k+1)+numn−j+1−i∗numn−j+1,前者可遞推得到。
代碼如下:
#include<stdio.h>
#define MAX_M (40005)
#define MAX_N (15005)
int num[MAX_N],suma[MAX_N],sumb[MAX_N],sumc[MAX_N],sumd[MAX_N],x[MAX_M];
int main()
{
freopen("magic.in","r",stdin);
freopen("magic.out","w",stdout);
int k,m,n;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
num[i]=suma[i]=sumb[i]=sumc[i]=sumd[i]=0;
for(int i=1;i<=m;i++)
scanf("%d",&x[i]),num[x[i]]++;
for(int i=1;i*9<n-1;i++)
{
k=0;
for(int id=n;id-i*9>1;id--)
k+=num[id-i]*num[id],
suma[id-i*9-1]+=num[id-i*7-1]*k,
sumb[id-i*7-1]+=num[id-i*9-1]*k;
k=0;
for(int ia=1;ia+i*9<n;ia++)
k+=num[ia]*num[ia+i*2],
sumc[ia+i*8+1]+=num[ia+i*9+1]*k,
sumd[ia+i*9+1]+=num[ia+i*8+1]*k;
}
for(int i=1;i<=m;i++)
printf("%d %d %d %d\n",suma[x[i]],sumb[x[i]],sumc[x[i]],sumd[x[i]]);
return 0;
}