BZOJ 3434 [Wc2014]时空穿梭

题目链接https://lydsy.com/JudgeOnline/problem.php?id=3434题解枚举选取的第一个点和最后一个点的坐标差∑ΔP=(Δx1,Δx2,⋯ ,Δxn)(gcd⁡(ΔP)−1c−2)∏k=1n(mi−Δxi+1)\sum_{\Delta P=(\Delta x_1,\Delta x_2,\cdots,\Delta x_n)}...
摘要由CSDN通过智能技术生成

题目链接

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

题解

枚举选取的第一个点和最后一个点的坐标差
∑ Δ P = ( Δ x 1 , Δ x 2 , ⋯   , Δ x n ) ( gcd ⁡ ( Δ P ) − 1 c − 2 ) ∏ k = 1 n ( m i − Δ x i + 1 ) \sum_{\Delta P=(\Delta x_1,\Delta x_2,\cdots,\Delta x_n)}\binom{\gcd(\Delta P)-1}{c-2}\prod_{k=1}^n (m_i-\Delta x_i+1) ΔP=(Δx1,Δx2,,Δxn)(c2gcd(ΔP)1)k=1n(miΔxi+1)
反演得到
∑ T = 1 min ⁡ i = 1 n m i g ( c , T ) ∏ i = 1 n f ( m i , T ) \sum_{T=1}^{\min_{i=1}^n m_i}g(c,T)\prod_{i=1}^n f(m_i,T) T=1mini=1nmig(c,T)i=1nf(mi,T)
其中
f ( m , T ) = − ⌊ m T ⌋ ( ⌊ m T ⌋ + 1 ) 2 T + m ⌊ m T ⌋ g ( c , T ) = ∑ d ∣ T ( d − 1 c − 2 ) μ ( T d ) f(m,T)=-\frac{\lfloor\frac{m}{T}\rfloor(\lfloor\frac{m}{T}\rfloor+1)}{2}T+m\lfloor\frac{m}{T}\rfloor\\ g(c,T)=\sum_{d|T}\binom{d-1}{c-2}\mu(\frac{T}{d}) f(m,T)=2Tm(Tm+1)T+mTmg(c,T)=dT(c2d1)μ(dT)
观察发现
∏ i = 1 n f ( m i , T ) \prod_{i=1}^n f(m_i,T) i=1nf(mi,T)
可以看作一个关于 T T T n n n次多项式,每一项的系数最多只有 ∑ i = 1 n m i \sum_{i=1}^n \sqrt{m_i} i=1nmi 种,因此可以整除分块分别求系数。假设求出的系数分别为 a 0 , a 1 , ⋯   , a n a_0,a_1,\cdots ,a_n a0,a1,,an,那么答案就是
∑ i = 0 n a i H ( c , i , min ⁡ i = 1 n m i ) \sum_{i=0}^n a_i H(c,i,\min_{i=1}^n m_i) i=0naiH(c,i,i=1minnmi)
其中
H ( c , i , k ) = ∑ T = 1 k g ( c , T ) T i H(c,i,k)=\sum_{T=1}^k g(c,T)T^i H(c,i,k)=T=1kg(c,T)Ti
可以预处理出 H H H

时间复杂度 O ( n c m + ∑ n 2 ∑ i = 1 n m i ) O(ncm+\sum n^2\sum_{i=1}^n \sqrt{m_i}) O(ncm+n2i=1nmi )

代码

#include <cstdio>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=11;
const int maxc=20;
const int maxm=100000;
const int mod=10007;
const int inf=0x3f3f3f3f;

int p[maxm+10],prime[maxm+10],cnt,mu[maxm+10],C[maxm+10][maxc+2],g[maxc+2][maxm+10],h[maxc+2][maxn+2][maxm+10],power[maxm+10][maxn+2];

int getprime()
{
  p[1]=mu[1]=1;
  for(int i=2; i<=maxm; ++i)
    {
      if(!p[i])
        {
          prime[++cnt]=i;
          mu[i]=mod-1;
        }
      for(int j=1; (j<=cnt)&&(i*prime[j]<=maxm); ++j)
        {
          int x=i*prime[j];
          p[x]=1;
          if(i%prime[j]==0)
            {
              mu[x]=0;
              break;
            }
          mu[x]=mod-mu[i];
        }
    }
  for(int i=0; i<=maxm; ++i)
    {
      C[i][0]=1;
      for(int j=1; (j<=maxc)&&(j<=i); ++j)
        {
          C[i][j]=C[i-1][j]+C[i-1][j-1];
          if(C[i][j]>=mod)
            {
              C[i][j]-=mod;
            }
        }
    }
  for(int i=1; i<=maxm; ++i)
    {
      power[i][0]=1;
      for(int j=1; j<=maxn; ++j)
        {
          power[i][j]=power[i][j-1]*i%mod;
        }
    }
  for(int c=2; c<=maxc; ++c)
    {
      for(int d=1; d<=maxm; ++d)
        {
          for(int T=d; T<=maxm; T+=d)
            {
              g[c][T]=(g[c][T]+C[d-1][c-2]*mu[T/d])%mod;
            }
        }
    }
  for(int c=2; c<=maxc; ++c)
    {
      for(int i=0; i<=maxn; ++i)
        {
          for(int k=1; k<=maxm; ++k)
            {
              h[c][i][k]=(h[c][i][k-1]+g[c][k]*power[k][i])%mod;
            }
        }
    }
  return 0;
}

int T,n,c,m[maxn+2],minm,a[maxn+2];

int main()
{
  getprime();
  T=read();
  while(T--)
    {
      n=read();
      c=read();
      minm=inf;
      for(int i=1; i<=n; ++i)
        {
          m[i]=read();
          minm=std::min(minm,m[i]);
        }
      int ans=0;
      for(int l=1,r; l<=minm; l=r+1)
        {
          r=inf;
          for(int i=1; i<=n; ++i)
            {
              r=std::min(r,m[i]/(m[i]/l));
            }
          for(int i=0; i<=n; ++i)
            {
              a[i]=(i==0);
            }
          for(int i=1; i<=n; ++i)
            {
              int k=m[i]/l,x=1ll*m[i]*k%mod,y=(1ll*k*(k+1)/2)%mod*(mod-1)%mod;
              for(int j=n; j; --j)
                {
                  a[j]=(x*a[j]+y*a[j-1])%mod;
                }
              a[0]=a[0]*m[i]%mod*k%mod;
            }
          for(int i=0; i<=n; ++i)
            {
              ans=(ans+a[i]*(h[c][i][r]-h[c][i][l-1]+mod))%mod;
            }
        }
      printf("%d\n",ans);
    }
  return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值