• 【BZOJ】3434: [Wc2014]时空穿梭


    http://www.lydsy.com/JudgeOnline/problem.php?id=3434

    题意:n维坐标中要找c个点使得c个点在一条线上且每一维的坐标单调递增且不能超过每一维限定的值m[i](n<=11, 2<=c<=20, m[i]<=100000)

    #include <bits/stdc++.h>
    using namespace std;
    const int N=100005, MD=10007;
    int C[N][19], g[21][N], f[21][12][N], a[12], p[N], pcnt, mu[N], MN;
    bool np[N];
    inline void check(int &x) { if(x>=MD || x<=-MD) x%=MD; }
    void init() {
    	mu[1]=1;
    	for(int i=2; i<=MN; ++i) {
    		if(!np[i]) p[++pcnt]=i, mu[i]=-1;
    		for(int j=1; j<=pcnt; ++j) {
    			int t=i*p[j]; if(t>MN) break;
    			np[t]=1;
    			if(i%p[j]==0) { mu[t]=0; break; }
    			mu[t]=-mu[i];
    		}
    	}
    	C[0][0]=1;
    	for(int i=1; i<=MN; ++i) {
    		C[i][0]=1;
    		for(int j=1; j<19; ++j) C[i][j]=C[i-1][j-1]+C[i-1][j], check(C[i][j]);
    	}
    	for(int c=2; c<=20; ++c)
    		for(int i=1; i<=MN; ++i)
    			for(int j=i, k=1; j<=MN; j+=i, ++k)
    				g[c][j]+=C[i-1][c-2]*mu[k], check(g[c][j]);
    	for(int i=1; i<=MN; ++i)
    		for(int c=2; c<=20; ++c) {
    			int t=1;
    			for(int j=0; j<=11; ++j) {
    				f[c][j][i]=t*g[c][i]+f[c][j][i-1];
    				t*=i; check(t); check(f[c][j][i]);
    			}
    		}
    }
    int nn[1005], cc[1005], mm[1005][12], m[12], n, c;
    typedef long long ll;
    inline void cal(const int &xx) {
    	memset(a, 0, sizeof a);
    	a[0]=1;
    	static int b, bb, i, t, k;
    	for(k=0; k<n; ++k) {
    		t=m[k]/xx;
    		b=((ll)t*m[k])%MD; bb=-(((ll)t*(t+1))>>1)%MD;
    		for(i=n; i>=1; --i)
    			a[i]=(a[i]*b+a[i-1]*bb)%MD, check(a[i]);
    		a[0]*=b; check(a[0]);
    	}
    }
    int main() {
    	int T;
    	scanf("%d", &T);
    	for(int cs=1; cs<=T; ++cs) {
    		scanf("%d%d", &nn[cs], &cc[cs]);
    		for(int i=0; i<nn[cs]; ++i)
    			scanf("%d", &mm[cs][i]), MN=max(MN, mm[cs][i]);
    	}
    	init();
    	for(int cs=1; cs<=T; ++cs) {
    		n=nn[cs]; c=cc[cs];
    		int mx=~0u>>1, ans=0;
    		for(int i=0; i<n; ++i) m[i]=mm[cs][i], mx=min(mx, m[i]);
    		for(int i=1, pos=0; i<=mx; i=pos+1) {
    			pos=mx+1;
    			for(int d=0; d<n; ++d) pos=min(pos, m[d]/(m[d]/i));
    			cal(i);
    			for(int d=0; d<=n; ++d) ans+=a[d]*(f[c][d][pos]-f[c][d][i-1]), check(ans);
    		}
    		printf("%d
    ", ((ans%MD)+MD)%MD);
    	}
    	return 0;
    }
    

      

    题解:

    我真的不想写公式了= =QAQ

    本题最神的两个地方,也就是我没有想到的地方:

    1、问题的转化:我们只需要在这些多维空间中确定两个端点,那么所有的点一定在这两个端点的线段上边就是了,而且不会重合。那么我们可以枚举两个端点的坐标差$i和j$(为了方便我们先设二维的,然后再推广),由于线端上整点的的数目就是$gcd(i, j)-1$(不包含端点),所以我们可以立即得到公式(待会写)。

    2、公式的处理。由于推出公式后,会发现有一部分不能分块QAQ,因为是枚举$gcd$,而式子里边存在着乘法.....因此稍加处理(下边写)..

    那么本题如果没有以上两点就是纯水题了.....

    一下均设$m[i]<=m[j], i<=j$,因为这是没有影响的,下标是二维的情形

    容易得到公式:

    $$
    egin{align}
    ans
    = & sum_{i=1}^{m[1]} sum_{j=1}^{m[2]} (m[1]-i)(m[2]-j) inom{(i, j)-1}{c-2} \
    = & sum_{d=1}^{m[1]} sum_{i=1}^{ left lfloor m[1]/d ight floor } sum_{j=1}^{ left lfloor m[2]/d ight floor } [(i, j)=1] (m[1]-id)(m[2]-jd) inom{d-1}{c-2} \
    end{align}
    $$

    $$ f(d) = sum_{i=1}^{ left lfloor m[1]/d ight floor } sum_{j=1}^{ left lfloor m[2]/d ight floor }
    [(i, j)=1] (m[1]-id)(m[2]-jd) $$
    $$ F(d) = sum_{i=1}^{ left lfloor m[1]/d ight floor } sum_{j=1}^{ left lfloor m[2]/d ight floor }
    (m[1]-id)(m[2]-jd) $$

    $F(d)$计算的是$(i, j)=kd$时情况,$f(d)$计算的是$(i, j)=d$时的情况,所以

    $$ F(d) = sum_{d|n} f(n) $$

    那么就能反演啦...即

    $$ f(d) = sum_{d|n} mu ( frac{n}{d} ) F(n) $$

    最后推得:

    $$
    ans = sum_{i=1}^{m[1]} left( left lfloor frac{m[1]}{i} ight floor m[1] - i frac{ left lfloor frac{m[1]}{i} ight floor ( left lfloor frac{m[1]}{i} ight floor + 1 ) }{2} ight) left( left lfloor frac{m[2]}{i} ight floor m[2] - i frac{ left lfloor frac{m[2]}{i} ight floor ( left lfloor frac{m[2]}{i} ight floor + 1 ) }{2} ight) sum_{d|i} mu ( frac{i}{d} ) inom{i-1}{c-2}
    $$

    发现后边和$m$是无关的= =,因此拓展就是将前边的东西合起来= =,即

    $$
    ans = sum_{i=1}^{m[1]} prod_{j=1}^{n} left( left lfloor frac{m[j]}{i} ight floor m[j] - i frac{ left lfloor frac{m[j]}{i} ight floor ( left lfloor frac{m[j]}{i} ight floor + 1 ) }{2} ight) sum_{d|i} mu ( frac{i}{d} ) inom{i-1}{c-2}
    $$

    $$ g(i) = sum_{d|i} mu ( frac{i}{d} ) inom{i-1}{c-2} $$

    然后$O(nlnn)$的暴力求出$g(i)$你总会的吧= =

    但是现在关键是答案里面有个$i$的乘法因子 QAQ否则就能直接出解了..

    可是发现这样乘起来是关于$i$的多项式...那么设系数向量$a$,且仅当$ left lfloor frac{m[j]}{i} ight floor 不变时 $,有

    $$
    sum_{j=0}^{n} a_ji^j =
    prod_{j=1}^{n} left( left lfloor frac{m[j]}{i} ight floor m[j] - i frac{ left lfloor frac{m[j]}{i} ight floor ( left lfloor frac{m[j]}{i} ight floor + 1 ) }{2} ight)
    $$

    最后原式变为

    $$
    egin{align}
    ans_x
    = & sum_{i=1}^{m[1]} sum_{j=0}^{n} a_ji^j g(i) \
    = & sum_{j=0}^{n} a_j sum_{i=1}^{m[1]} i^j g(i) \
    end{align}
    $$

    然后暴力预处理你怕不怕= =

    时间复杂度为:$O(cmlog(n)+Tn^3sqrt{m})$

  • 相关阅读:
    用JavaScript 实现变速回到顶部
    导出数据到Excel
    Jquery ajax调用webService,远程访问出错解决办法
    火狐和IE的window.event对象详解
    硬盘、U盘添加漂亮背景
    JS 获取当前日期时间(兼容IE FF)
    Base64编码
    师生关系
    关于计算机导论的问题
    自我介绍
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4271303.html
Copyright © 2020-2023  润新知