• [题解] LuoguP3702 [SDOI2017]序列计数


    https://www.luogu.com.cn/problem/P3702

    稍微有点套路......

    先不管那个质数的条件

    考虑(DP),令(f_{i,j})表示(i)个数和(\%p)(j)的方案数。

    有转移

    [f_{i,c}=sumlimits_{(a+b) \% p = c} f_{i-1,a}f_{i-1,b} ]

    但这样转移(i)就有(10^9)个...

    注意到如果我们没必要从(i-1)转移到(i)

    如果知道了(f_i),那么我们可以推到(f_{2i}),即

    [f_{2i,c}=sumlimits_{(a+b) \% p=c} f_{i,a}f_{i,b} ]

    进一步的如果我们知道(f_i,f_j),可以推到

    [f_{i+j,c}=sumlimits_{(a+b) \% p = c}f_{i,a}f_{j,b} ]

    可以像快速幂那样倍增转移,边界就是(f_{1,i}=1...m)(\% p = i)的数的个数。

    然后发现这样选出来的不一定合法,减掉没有素数构成的序列个数就好了(这个可以和上面类似的(DP))。

    所以这个(p)可以搞到(10^5)的样子然后FFT转移的吧......

    但这里暴力卷积就好了....

    复杂度(O(p^2 log n))

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 210, mod = 20170408;
    
    int p;
    
    struct poly {
      int a[N];
      poly() { memset(a, 0, sizeof(a)); }
      
      inline int &operator [] (int i) { return a[i]; }
      inline int operator [] (int i) const { return a[i]; }
      
      poly operator * (const poly &o) const {
        static int A[N];
        for (int i = 0; i <= p * 2; i++) A[i] = 0;
        for (int i = 0; i < p; i++)
          for (int j = 0; j < p; j++) {
            int k = (i+j) % p; A[k] += 1ll * a[i] * o[j] % mod;
            if (A[k] >= mod) A[k] -= mod;
          }
        poly ans;
        for (int i = 0; i < p; i++) ans[i] = A[i];
        return ans;
      }
    };
    
    poly qpow(poly A, int n) {
      poly ans; ans[0] = 1;
      for (; n; n >>= 1, A = A * A)
        if (n & 1) ans = ans * A;
      return ans;
    }
    
    vector<int> ps;
    bool vis[20000010];
    
    void sieve(int n) {
      for (int i = 2; i <= n; i++) {
        if (!vis[i]) ps.push_back(i);
        for (auto j : ps) {
          if (i * j > n) break;
          vis[i*j] = 1; if (i % j == 0) break;
        }
      }
    }
    
    int n, m;
    poly A, B, ans1, ans2;
    
    int main() {
      scanf("%d%d%d", &n, &m, &p);
      sieve(m);
      for (int i = 1; i <= m; i++) ++A[i % p], ++B[i % p];
      for (auto pr : ps) --B[pr % p];
      ans1 = qpow(A, n), ans2 = qpow(B, n);
      printf("%d
    ", (ans1[0] - ans2[0] + mod) % mod);
      return 0;
    }
    
    
  • 相关阅读:
    服务器时钟同步
    vue父组件向子组件传递数值 props
    sql 语句in 使用占位符
    vagrant 打包box 快速部署统一开发环境
    Memcache安装使用 linux系统
    centos 7 搭建lnmp环境搭建 yum 源安装
    vagrant搭建lnmp 环境(环境contos7+php72w+mariaDB10.2)
    linux定时任务 Cron Crontab命令
    vue使用el-upload 跨域上传文件跳坑小记
    vue key得理解
  • 原文地址:https://www.cnblogs.com/wxq1229/p/12804726.html
Copyright © 2020-2023  润新知