zoukankan      html  css  js  c++  java
  • Luogu 2822[NOIP2016] 组合数问题

    题解

    乱搞就能过了。

    首先我们考虑如何快速判断C(i, j ) | k 是否成立。

    由于$k$非常小, 所以可以对$k$分解质因数, 接着预处理出前N个数的阶乘的因数中 $p_i$ 的个数, 然后就可以$O(1)$判断C(i,j)| k 

    然后用mk[i][j] 记录 C(i, j) | k , 并将它转化为二位前缀和, 每次查询只需要输出mk[ n ][ m ]即可

    预处理时间复杂度:$O(NlnN + NM)$

    每次查询$O(1)$

    代码

     1 #include<cstring>
     2 #include<cmath>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #define rd read()
     6 
     7 const int N = 2e3 + 5;
     8 
     9 int T, k, n, m;
    10 int pri[5], cnt[5], tot;
    11 int num[N][5], mk[N][N];
    12 
    13 int read() {
    14     int X = 0, p = 1; char c = getchar();
    15     for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
    16     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
    17     return X * p;
    18 }
    19 
    20 int fpow(int a, int b) {
    21     int re = 1;
    22     for(; b; b >>= 1, a *= a) if(b & 1) re *= a;
    23     return re;
    24 }
    25 
    26 int jud(int x, int y) {
    27     for(int i = 1; i <= tot; ++i) {
    28         int re = 0;
    29         re += num[x][i];
    30         re -= num[y][i];
    31         re -= num[x - y][i];
    32         if(re < cnt[i]) return 0;
    33     }
    34     return 1;
    35 }
    36 
    37 void init() {
    38     int t = k;
    39     for(int i = 2; i <= k; ++i) if(t % i == 0) {
    40         pri[++tot] = i;
    41         while(t % i == 0) cnt[tot]++, t /= i;
    42     }
    43     for(int j = 1; j <= tot; ++j) 
    44         for(int l = 1; ; ++l) {
    45             int p = fpow(pri[j], l);
    46             if(p >= N) break;
    47             for(int i = 1; i < N; ++i) num[i][j] += i / p;
    48         }
    49     for(int i = 1; i < N; ++i)
    50         for(int j = 1; j <= i; ++j) if(jud(i, j)) mk[i][j] = 1;
    51     for(int i = 1; i < N; ++i)
    52         for(int j = 1; j < N; ++j) mk[i][j] += mk[i - 1][j];
    53     for(int i = 1; i < N; ++i)
    54         for(int j = 1; j < N; ++j) mk[i][j] += mk[i][j - 1];
    55 }
    56 
    57 int main()
    58 {
    59     T = rd; k = rd;
    60     init();
    61     for(; T; T--) {
    62         n = rd; m = rd;
    63         printf("%d
    ", mk[n][m]);
    64     }
    65 }
    View Code
  • 相关阅读:
    !!!!Linux系统开发 系列 4 进程资源 环境 fork()子进程 wait() waitpid()僵尸 孤儿进程
    linux运维工程师
    C# CSGL
    C# 中的"yield"使用
    C#语法糖
    VS2017下Git的使用
    Oracle数据类型与.NET中的对应关系
    Java 8 Stream
    Java 8 默认方法
    Java 8 函数式接口
  • 原文地址:https://www.cnblogs.com/cychester/p/9528170.html
Copyright © 2011-2022 走看看