NOIP2016P4 魔法陣 題解

(題目描述略)

設魔法值爲 j 物品 numjnum_j 個,則魔法陣 xa,xb,xc,xdx_a, x_b, x_c, x_d 對於 A, B, C, D 物品貢獻分別爲 numxbnumxcnumxd,numxanumxcnumxd,numxanumxbnumxd,numxanumxbnumxcnum_{xb} * num_{xc} * num_{xd}, num_{xa} * num_{xc} * num_{xd}, num_{xa} * num_{xb} * num_{xd}, num_{xa} * num_{xb} * num_{xc}。設 i=xdxci = x_d - x_c,則 xbxa=2ix_b - x_a = 2ixcxb>6ix_c - x_b > 6ixdxb>7ix_d - x_b > 7ixcxa>8ix_c - x_a > 8ixdxa>9ix_d - x_a > 9i。枚舉 i[1,n19]i \in [1, \lfloor \frac{n - 1}9 \rfloor],並枚舉 xa,xdx_a, x_d 使得 1xaxdn1 ≤ x_a ≤ x_d ≤ nxdxa>9ix_d - x_a > 9i,由 xb=xa+2ix_b = x_a + 2ixc=xdix_c = x_d - i 得出每組可能 xa,xb,xc,xdx_a, x_b, x_c, x_d 統計即可,這樣可得 85 分。

對於滿分算法,考慮當 xa=n9i1x_a = n - 9i - 1,即 xb=n7i1x_b = n - 7i -1 時,相應 {xc=nixd=n\begin{cases} x_c = n - i \\ x_d = n \end{cases};當 {xa=n9i2xb=n7i2\begin{cases} x_a = n - 9i - 2 \\ x_b = n - 7i - 2 \end{cases} 時,相應 {xc=nixd=n\begin{cases} x_c = n - i \\ x_d = n \end{cases}{xc=n1ixd=n1\begin{cases} x_c = n - 1 - i \\ x_d = n - 1 \end{cases}。一般的,當 {xa=n9ijxb=n7ij(1j<n9i)\begin{cases} x_a = n - 9i - j \\ x_b = n - 7i - j \end{cases}(1 ≤ j < n - 9i) 時,相應 xc,xdx_c, x_d 解集爲 {xa=n9ij+1xb=n7ij+1\begin{cases} x_a = n - 9i - j + 1 \\ x_b = n - 7i - j + 1 \end{cases} 解集和 {xc=nj+1ixd=nj+1\begin{cases} x_c = n - j + 1 - i \\ x_d = n - j + 1 \end{cases} 的並集,對於 A, B 物品貢獻分別爲 numxbk=1j(numnk+1inumnk+1)num_{xb} * \sum_{k = 1}^j (num_{n - k + 1 - i} * num_{n - k + 1})numxak=1j(numnk+1inumnk+1)num_{xa} * \sum_{k = 1}^j (num_{n - k + 1 - i} * num_{n - k + 1}),而 k=1j(numnk+1inumnk+1)=k=1j1(numnk+1inumnk+1)+numnj+1inumnj+1\sum_{k = 1}^j (num_{n - k + 1 - i} * num_{n - k + 1}) = \sum_{k = 1}^{j - 1} (num_{n - k + 1 - i} * num_{n - k + 1}) + num_{n - j + 1 - i} * num_{n - 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章