我们考虑怎么选取c个点满足有直线同时经过他们
设
Ai
表示第i个点,用向量
bi=(x1,x2,x3...xn)
表示
Ai+1
与
Ai
的差
由于每一维的
vi(xi=pi+tvi)
是不变的,对于相邻的两个点,
Δt
是相同的,所以任一向量
bi=(x1,x2,x3...xn)
,
xi
之间的比值是不变的,即
vi
之间的比值,所以对于任一向量
bi=(x1,x2,x3...xn)
,都可以将它写成
bi=(Δt∗v1,Δt∗v2...Δt∗vn)
,将
vi
之间的比值写成整数
ai
之间的比值,得
bi=(k∗c1,k∗c2,...k∗cn)
我们考虑枚举每一维的极差
a1,a2,...an
,设
d=gcd(a1,a2,...an)
,则
ai=ci∗d
,则将
d
分给这
因为所有坐标为正整数,第
i
维坐标不超过
设
mi=Mi−1
所以有
=∑dCc−2d−1∏ni=1∑⌊mid⌋ai=1(Mi−aid) ϵ((a1,a2,...an)=1)
反演一下
=∑dCc−2d−1∏ni=1∑⌊mid⌋ai=1(Mi−aid)∑D|(a1,a2...an)μ(D)
=∑dCc−2d−1∑Dμ(D)∏ni=1∑⌊miDd⌋ai=1(Mi−aiDd)
枚举
D=Dd
=∑D∑d|DCc−2d−1μ(Dd)∏ni=1∑⌊miD⌋ai=1(Mi−aiD)
可以发现
f(D,c)=∑d|DCc−2d−1μ(Dd)
这个东西只与
D
与
到这里,因为后面的柿子和D仍然相关,仍然需要枚举
m
个
观察
∏ni=1∑⌊miD⌋ai=1(Mi−aiD)
这个东西,可以化成
∏ni=1Mi⌊miD⌋−(D+D⌊miD⌋)⌊miD⌋2
=∏ni=1Mi⌊miD⌋−D(1+⌊miD⌋)⌊miD⌋2
接着把这
n
个多项式相乘
所以在维护了 g(D,c,j)=f(D,c)Dj 的前缀和后,可以将原式按 ⌊miD⌋ 分成 O(nm−−√) 段,每段内暴力 O(n2) 展开多项式各项系数,乘上前面的柿子这一段的和
时间复杂度 O(nmc+cmlogm+Tn3m−−√)
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline void down(int &x,const int y){if(x>y)x=y;}
const int maxn = 12;
const int maxc = 21;
const int maxm = 110000;
const int Mod = 10007;
int p[maxm],pri,miu[maxm];
bool v[maxm];
int C[maxm][maxc],f[maxc][maxm],pg[maxc][maxm][maxn];
// miu*C pre G(i,c)×i^j
void pre()
{
C[0][0]=1;
for(int i=1;i<maxm;i++)
{
C[i][0]=1;
for(int j=1;j<maxc;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%Mod;
}
miu[1]=1; ///
for(int i=2;i<maxm;i++)
{
if(!v[i]) miu[i]=-1,p[++pri]=i;
for(int j=1;j<=pri;j++)
{
int k=i*p[j];
if(k>=maxm) break;
v[k]=true;
if(i%p[j]==0) break;
miu[k]=-miu[i];
}
}
for(int c=2;c<maxc;c++)
{
for(int i=1;i<maxm;i++)
{
for(int j=i,ji=1;j<maxm;j+=i,ji++)
(f[c][j]+=C[i-1][c-2]*miu[ji]%Mod)%=Mod;
}
}
for(int c=2;c<maxc;c++)
{
for(int i=1;i<maxm;i++)
{
for(int j=0,ij=1;j<maxn;j++,ij=ij*i%Mod)
{
pg[c][i][j]=(pg[c][i-1][j]+f[c][i]*ij%Mod)%Mod;
}
}
}
}
int n,c;
int m[maxn];
int a[maxn],an;
int main()
{
pre();
int t; scanf("%d",&t);
while(t--)
{
int mn=maxm;
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++) scanf("%d",&m[i]),m[i]--,down(mn,m[i]);
int ret=0;
for(int i=1;i<=mn;)
{
int r=mn;
for(int j=1;j<=n;j++) down(r,m[j]/(m[j]/i));
a[an=0]=1;
for(int j=1;j<=n;j++)
{
int mi=(m[j]/i)%Mod;
int x1=(m[j]+1)*mi%Mod,x2=-mi*(mi+1)/2%Mod;
a[an+1]=a[an]*x2%Mod;
for(int l=an;l>=0;l--) a[l]=(a[l]*x1%Mod+(l?a[l-1]:0)*x2%Mod)%Mod;
an++;
}
for(int j=0;j<=an;j++) (ret+=a[j]*((pg[c][r][j]-pg[c][i-1][j])%Mod)%Mod)%=Mod;
i=r+1;
}
if(ret<0) ret+=Mod;
printf("%d\n",ret);
}
return 0;
}