Codechef CNTDSETS Counting D-sets

Link
为了防止算重,我们可以强制每一维的最小坐标都达到下限。
那么直径的限制也就变成了至少存在一个维度的最大坐标达到(d)
第二个限制很好去掉,设(f(d))为坐标范围为([0,d])的,每一维的最小坐标都达到下限的方案数,那么答案就是(f(d)-f(d-1))
然后用容斥有多少维可能满足第一个限制,(f(d)=sumlimits_{i=0}^n(-1)^i{nchoose i}2^{d^i(d+1)^{n-i}})

#include<cstdio>
const int P=1000000007;
int C[2001][2001];
int read(){int x;scanf("%d",&x);return x;}
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
void dec(int&a,int b){a-=b,a+=a>>31&P;}
int mul(int a,int b,int p){return 1ll*a*b%p;}
int pow(int a,int k,int p){int r=1;for(;k;k>>=1,a=mul(a,a,p))if(k&1)r=mul(a,r,p);return r;}
int f(int n,int d)
{
    int sum=0;
    for(int i=0;i<=n;++i) (i&1? dec:inc)(sum,mul(C[n][i],pow(2,mul(pow(d,i,P-1),pow(d+1,n-i,P-1),P-1),P),P));
    return sum;
} 
int main()
{
    for(int i=0;i<=2000;++i) for(int j=C[i][0]=1;j<=i;++j) inc(C[i][j]=C[i-1][j],C[i-1][j-1]);
    for(int T=read(),n,d;T;--T) n=read(),d=read(),printf("%d
",(f(n,d)-f(n,d-1)+P)%P);
} 
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12696388.html