• UOJ 54 【WC2014】时空穿梭——莫比乌斯反演


    题目:http://uoj.ac/problem/54

    想写20分。 Subtask 2 就是枚举4个维度的值的比例,可算对于一个比例有多少个值可以选,然后就是组合数。结果好像不对。

    因为模数太小,组合数不能用阶乘的那个公式。不过 c*m 递推即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    const int mod=10007;
    int Mn(int a,int b){return a<b?a:b;}
    int Mx(int a,int b){return a>b?a:b;}
    void upd(int &x){x>=mod?x-=mod:0;}
    int pw(int x,int k)
    {int ret=1;while(k){if(k&1)ret=ret*x%mod;x=x*x%mod;k>>=1;}return ret;}
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    
    const int N=15,M=1e5+5,Q=1005;
    int T,n[Q],k[Q],m[Q][N],c[M][35];
    void init_c(int n,int m)
    {
      for(int i=0;i<=n;i++)c[i][0]=1;
      for(int i=1;i<=n;i++)
        for(int j=1,k=Mn(i,m);j<=k;j++)
          c[i][j]=c[i-1][j]+c[i-1][j-1],upd(c[i][j]);
    }
    void solve1()
    {
      init_c(100000,20);
      for(int t=1;t<=T;t++) printf("%d
    ",c[m[t][1]][k[t]]);
    }
    int cs[5],ans;
    void dfs(int cr,int bh)
    {
      if(cr>n[bh])
        {
          int mn=35;
          for(int i=1;i<=n[bh];i++)
        mn=Mn(mn,m[bh][i]/cs[i]);
          ans+=c[mn][n[bh]];upd(ans); return;
        }
      for(int i=1,lm=m[bh][cr];i<=lm;i++)
        {
          bool flag=1;
          for(int j=1;j<cr;j++)
        if(gcd(cs[j],i)>1){flag=0;break;}
          if(flag)cs[cr]=i,dfs(cr+1,bh);
        }
    }
    void solve3()
    {
      init_c(30,20);
      for(int t=1;t<=T;t++)
        {
          ans=0;dfs(1,t);printf("%d
    ",ans);
        }
    }
    int main()
    {
      T=rdn();bool fg1=0,fg3=0;
      for(int t=1;t<=T;t++)
        {
          n[t]=rdn();k[t]=rdn();
          fg1|=(n[t]!=1);
          for(int i=1;i<=n[t];i++)m[t][i]=rdn(),fg3|=(m[t][i]>30);
        }
      if(!fg1){solve1();return 0;}
      if(!fg3){solve3();return 0;}
      return 0;
    }
    View Code

    正解是在枚举一组答案里的距离最远的两个点。可选的位置就是每一维的差值 xi 的 gcd +1 ,方案就是 ( C_{gcd-1}^{c-2} * prod_{i=1}^{n}(m_{i}-x_{i}) ) ;然后反演一番之类的。

    https://www.cnblogs.com/Zinn/p/10272661.html

    当出现 ( prod(m_{i}leftlfloorfrac{m_{i}}{D} ight floor - Dfrac{(1+leftlfloorfrac{m_{i}}{D} ight floor)leftlfloorfrac{m_{i}}{D} ight floor}{2} ) 的时候,因为除了 D 以外的部分可以分块,所以把它看成关于 D 的多项式的想法很好。

    虽然模数是 10007 ,两个乘起来也不会爆 int ,但 m[ i ] 很大,所以还是得到处写 (ll) 。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=15,C=25,M=1e5+5,mod=10007;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    void upd(int &x){x>=mod?x-=mod:0;x<0?x+=mod:0;}
    int pw(int x,int k){int ret=1;while(k){if(k&1)ret=ret*x%mod;x=x*x%mod;k>>=1;}return ret;}
    
    int T,c[M][C],u[M],f[N][C][M],pri[M],cnt;bool vis[M];
    void init()
    {
      int n=11,nc=20,m=1e5;
      u[1]=1;
      for(int i=2;i<=m;i++)
        {
          if(!vis[i])pri[++cnt]=i,u[i]=-1;
          for(int j=1,d;j<=cnt&&(d=i*pri[j])<=m;j++)
        {
          vis[d]=1;if(i%pri[j])u[d]=-u[i];else {u[d]=0;break;}
        }
        }
      for(int i=0;i<m;i++)c[i][0]=1;
      for(int k=nc-2,i=1;i<k;i++)
        for(int j=1;j<=i;j++)c[i][j]=c[i-1][j]+c[i-1][j-1],upd(c[i][j]);
      for(int k=nc-2,i=k;i<m;i++)
        for(int j=1;j<=k;j++)c[i][j]=c[i-1][j]+c[i-1][j-1],upd(c[i][j]);
      for(int tc=2;tc<=nc;tc++)
        {
          for(int i=1;i<=m;i++)
        for(int j=i,k=1;j<=m;j+=i,k++)
          f[0][tc][j]+=c[i-1][tc-2]*u[k],upd(f[0][tc][j]);
          for(int j=1;j<=m;j++)
        for(int i=1;i<=n;i++)f[i][tc][j]=f[i-1][tc][j]*j%mod;
        }
      for(int i=0;i<=n;i++)
        for(int tc=2;tc<=nc;tc++)
          for(int j=1;j<=m;j++)f[i][tc][j]+=f[i][tc][j-1],upd(f[i][tc][j]);
    }
    int n,tc,a[N],m[N],tm[N];
    void cz(int bh)
    {
      memset(a,0,sizeof a);a[0]=1;
      for(int i=1;i<=n;i++)
        {
          int x=((ll)tm[i]*(tm[i]+1)>>1)%mod, y=(ll)tm[i]*m[i]%mod;//(ll)!!!
          x=-x; upd(x);//
          for(int j=n;j;j--)//--!!!
        a[j]=((ll)a[j-1]*x+(ll)a[j]*y)%mod;
          a[0]=a[0]*y%mod;
        }
    }
    int cal()
    {
      int ret=0;
      int lm=m[1];for(int i=2;i<=n;i++)lm=Mn(lm,m[i]);
      for(int i=1,nt;i<=lm;i=nt+1)
        {
          nt=lm;for(int j=1;j<=n;j++)tm[j]=m[j]/i,nt=Mn(nt,m[j]/tm[j]);
          cz(i);
          for(int j=0;j<=n;j++)ret=(ret+a[j]*(f[j][tc][nt]-f[j][tc][i-1]))%mod,upd(ret);
        }
      return ret;
    }
    int main()
    {
      init();T=rdn();
      while(T--)
        {
          n=rdn();tc=rdn();for(int i=1;i<=n;i++)m[i]=rdn();
          if(tc==1)
        {
          int ret=1;for(int i=1;i<=n;i++)ret=ret*m[i]%mod;printf("%d
    ",ret);
        }
          else printf("%d
    ",cal());
        }
      return 0;
    }
  • 相关阅读:
    Flask特殊装饰器
    flask中的Response、Request、Session、装饰器、实例化参数、蓝图、
    QC的安装和配置
    测试用例设计方法-因果图(鱼骨图)
    测试用例设计方法-流程分析法(场景法)
    测试用例设计方法-状态迁移
    测试用例设计方法-正交实验
    测试用例设计方法-判定表
    测试用例设计方法-边界值
    测试用例设计方法-等价类划分
  • 原文地址:https://www.cnblogs.com/Narh/p/10273604.html
Copyright © 2020-2023  润新知