【题解】Counting D-sets(容斥+欧拉定理)

【题解】Counting D-sets(容斥+欧拉定理)

没时间写先咕咕咕。

vjCodeChef - CNTDSETS

就是容斥,只是难了一二三四五\(\dots \inf\)

题目大意:

给定你一个\(n\)维空间,问你这个空间内有多少个点集满足两点间最大的切比雪夫距离为\(d\)。两个点集不同,当且仅当两个点集无法通过平移而想等。

转化1

考虑最后那个限制,平移想等的限制,受这道题的启发【题解】At2370 Piling Up,我们考虑钦定每一维的\(0\)点都有点坐落,这样就钦定了一个基准,问题就转变成了要求每维都有\(0\),且存在某个点的某维坐标为\(d\),且\(d\)是所有数里最大的。

转化2

此类题有一个套路,就是当它钦定最大最小为\(d\)的时候的方案数,可以等于\([0,d]\)的随机分配\(-[0,d-1]\)的随机分配,这样减出来的方案就保证了一定有点在\(d\)空间的边界上,不然一定会被减去。

转化3

所以我们答案就是\(f(d)-f(d-1)\),其中\(f(d)\)表示\(n\)维空间的每维在\([0,d]\)中随意分配坐标的方案数。此时我们发现仍然有问题,因为我们还没有钦定每一维有\(0\)

考虑我们如何钦定每一维都有零,显然不能一个组合数直接钦定,因为可能一个点的坐标有多个\(0\),这个情况我们考虑不到。但是可以发现每一维本质相同的(意思是可以通过组合数来计算方案),所以可以\(O(n)\)容斥。考虑我们容斥什么,我们容斥钦定每至少i维没有\(0\),最后我们要的是\(0\)维没有\(0\)

转换4

我们看一个点的坐标,写成这个形式\(p(x_1,x_2,x_3,x_4\dots x_n),x_i\in [0,d],x_i \in N^+\),那么由\(p\)构成的点集的方案是多少呢,我想啊想想不出来就去看题解去了。题解告诉我,这个的方案数是

\[2^{(d+1)^n} \]

傻逼了。其实很简单,总共有\((d+1)^n\)个点,枚举每个点放不放即可,注意包括了一个也不放的方案。

那么如何钦定至少\(i\)没有\(0\)呢?很简单,钦定\(x_i\in[1,d]\)就好了。那么这个的方案就是

\[{n \choose i}2^{d^i(d+1)^{n-i}} \]

乘上一个组合数枚举哪些维度没有\(0\)

所以最终\(f(x)=\)

\[\sum_{i=0}^n (-1)^i{n \choose i}2^{d^i(d+1)^{n-i}} \]

所以最终答案\(=f(d)-f(d-1)\)

转换5

看答案那个式子,你发现你要到指数上面取膜,你很害怕,因为你好像不知道指数上取膜的运算规则。这就\(naive\)了,模数是\(1e9+7\)是个质数,现在你发现欧拉定理有用了,因为

\[a^{\phi(p)} \equiv 1 \mod p \]

而质数中,\(\phi(p)=p-1\)。所以你在指数上就直接对\(1e9+6\)取膜就好了。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>


using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}
const int mod=1e9+7;
inline int Pow(int base,const int&p){
      register int ret=1;
      for(register int t=p;t;t>>=1,base=1ll*base*base%mod)
	    if(t&1) ret=1ll*ret*base%mod;
      return ret;
}

const int mod2=mod-1;
inline int zhiPow(int base,const int&p){
      register int ret=1;
      for(register int t=p;t;t>>=1,base=1ll*base*base%mod2)
	    if(t&1) ret=1ll*ret*base%mod2;
      return ret;      
      
}

const int maxn=1e3+5;
int jc[maxn],inv[maxn];
int n,d;
inline int c(const int&n,const int&m){
      if(n<m)return 0;
      return 1ll*jc[n]*inv[m]%mod*1ll*inv[n-m]%mod;
}
inline int F(const int&x){
      register int ret=0;
      for(register int t=0,delta;t<=n;++t){
	    delta=1ll*c(n,t)*Pow(2,(1ll*zhiPow(x,t)*zhiPow(x+1,n-t))%mod2)%mod;
	    if(t&1) delta=mod-delta;
	    ret=(ret+delta)%mod;
      }
      return ret;
}


int main(){
#ifndef ONLINE_JUDGE
      freopen("in.in","r",stdin);
      //freopen("out.out","w",stdout);
#endif
      int T=qr();
      jc[0]=inv[0]=1;
      for(register int t=1;t<maxn;++t)
	    jc[t]=1ll*jc[t-1]*t%mod,inv[t]=Pow(jc[t],mod-2);
      while(T--){
	    n=qr(),d=qr();
	    cout<<((F(d)-F(d-1))%mod+mod)%mod<<endl;
      }
      return 0;
}

Status Accepted
Memory 15257kB
Length 1546
Lang C++14(gcc 6.3)
Submitted 2019-06-13 17:44:16
Shared Yes
RemoteRunId 24729181
posted @ 2019-06-13 17:49  谁是鸽王  阅读(276)  评论(0编辑  收藏  举报