calc BZOJ 2655

calc

【问题描述】

  一个序列a1,...,an是合法的,当且仅当:
  长度为给定的n。
  a1,...,an都是[1,A]中的整数。
  a1,...,an互不相等。
  一个序列的值定义为它里面所有数的乘积,即a1a2...an。
  求所有不同合法序列的值的和。
  两个序列不同当且仅当他们任意一位不一样。
  输出答案对一个数mod取余的结果。

【输入格式】

  一行3个数,A,n,mod。意义为上面所说的。

【输出格式】

  一行结果。

【样例输入】

9 7 10007

【样例输出】

3611

HINT

【数据规模】

  0:A<=10,n<=10。

  1..3:A<=1000,n<=20。

  4..9:A<=10^9,n<=20。

  10..19:A<=10^9,n<=500。。

  全部:mod<=10^9,并且mod为素数,mod>A>n+1。



题解:

主要算法:动态规划(Dp);拉格朗日插值法;

设 f[i][j] 为用不大于A的数组成的有序合法序列方案数

转移方程:(是否选取 i 这个数字)

题目要求无序,那么最后乘上 n! 即可

细心观察一小下,发现它是一个有 2n 项的多项式

用拉格朗日插值法:

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<algorithm>
 7 using namespace std;
 8 typedef long long lo;
 9 inline int Get()
10 {
11     int x;
12     char c;
13     bool o = false;
14     while((c = getchar()) < ‘0‘ || c > ‘9‘)
15         if(c == ‘-‘) o = true;
16     x = c - ‘0‘;
17     while((c = getchar()) >= ‘0‘ && c <= ‘9‘)
18         x = x * 10 + c - ‘0‘;
19     return (o) ? -x : x;
20 }
21 const int maxn = 2333;
22 int f[maxn][maxn];
23 int fac[maxn];
24 int x[maxn], y[maxn];
25 int a, n, m, mo;
26 int z, v, ans;
27 int num;
28 inline void Dp()
29 {
30     f[0][0] = 1;
31     for(int i = 1; i <= m; ++i)
32         for(int j = 0; j <= n; ++j)
33         {
34             f[i][j] = f[i - 1][j];
35             if(j) f[i][j] += (lo) f[i - 1][j - 1] * i % mo;
36             if(f[i][j] >= mo) f[i][j] -= mo;
37         }
38 }
39 inline void Fac()
40 {
41     fac[0] = 1;
42     for(int i = 1; i <= n; ++i) fac[i] = (lo) fac[i - 1] * i % mo;
43 }
44 inline void Sun()
45 {
46     num = 0;
47     for(int i = 0; i <= m; ++i)
48         if(f[i][n])
49         {
50             x[++num] = i, y[num] = f[i][n];
51             if(num == (n << 1 | 1)) return;
52         }
53 }
54 inline int Mod(int x)
55 {
56     if(x < 0) x += mo;
57     return x;
58 }
59 inline int Pow(int x, int n)
60 {
61     int sum = 1;
62     while(n)
63     {
64         if(n & 1) sum = (lo) sum * x % mo;
65         x = (lo) x * x % mo;
66         n >>= 1;
67     }
68     return sum;
69 }
70 int main()
71 {
72     a = Get(), n = Get(), mo = Get();
73     m = n << 2;
74     Dp();
75     Fac();
76     if(m >= a)
77     {
78         printf("%d", (lo) f[a][n] * fac[n] % mo);
79         return 0;
80     }
81     Sun();
82     z = 1;
83     for(int i = 1; i <= num; ++i) z = (lo) z * Mod(a - x[i]) % mo;
84     for(int i = 1; i <= num; ++i)
85     {
86         v = Mod(a - x[i]);
87         for(int j = 1; j <= num; ++j)
88             if(i != j)
89                 v = (lo) v * Mod(x[i] - x[j]) % mo;
90         ans = ans + (lo) y[i] * z % mo * Pow(v, mo - 2) % mo;
91         if(ans >= mo) ans -= mo;
92     }
93     printf("%d", (lo) ans * fac[n] % mo);
94 }
时间: 2024-09-29 01:00:54

calc BZOJ 2655的相关文章

bzoj[2655] calc

Description 一个序列a1,...,an是合法的,当且仅当: 长度为给定的n. a1,...,an都是[1,A]中的整数. a1,...,an互不相等. 一个序列的值定义为它里面所有数的乘积,即a1a2...an. 求所有不同合法序列的值的和. 两个序列不同当且仅当他们任意一位不一样. 输出答案对一个数mod取余的结果. Input 一行3个数,A,n,mod.意义为上面所说的. Output 一行结果. Sample Input 9 7 10007 Sample Output 361

【BZOJ】2655: calc 动态规划+拉格朗日插值

[题意]一个序列$a_1,...,a_n$合法当且仅当它们都是[1,A]中的数字且互不相同,一个序列的价值定义为数字的乘积,求所有序列的价值和.n<=500,A<=10^9,n+1<A<mod<=10^9,mod是素数. [算法]动态规划+拉格朗日插值 [题解]这道题每个数字的贡献和序列选了的数字积关系密切,所以不能从序列角度考虑(和具体数字关系不大). 设$f_{n,m}$表示前n个数字(值域)中取m个数字的答案,那么枚举取或不取数字n,取n时乘n且有j个位置可以插入,即:

bzoj 2506 calc 题解

[原题] 2506: calc Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 228  Solved: 112 Description 给一个长度为n的非负整数序列A1,A2,-,An.现有m个询问,每次询问给出l,r,p,k,问满足l<=i<=r且Ai mod p = k的值i的个数. Input 第一行两个正整数n和m. 第二行n个数,表示A1,A2,-,An. 以下m行,每行四个数分别表示l,r,p,k.满足1<=l<=r&

bzoj千题计划269:bzoj2655: calc

http://www.lydsy.com/JudgeOnline/problem.php?id=2655 f[i][j] 表示[1,i]里选严格递增的j个数,序列值之和 那么ans=f[A][n] *  n! A太大,那么用拉格朗日插值法 f[i][j] 是关于i的2j次多项式,证明如下: %%%rqy #include<cstdio> using namespace std; int mod; int f[1510][501]; int x[1005],y[1005],tot; int Po

BZOJ 2506 calc

离线+权值分块.无法在线,每个节点存不下100*100. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100500 #define maxm 10500 using namespace std; struct query { int pos,id,val,a,b; }q[maxn*3]; int n,m,cnt[maxm],a[m

BZOJ 2671 Calc 数论

题目大意:给定N,求∑ni=1∑nj=1[i+j|ij]1 跪Nodgd= = 不妨设d=gcd(i,j),i=ad,j=bd,gcd(a,b)=1,那么有 (a+b)d|abd2 即 a+b|abd ∵gcd(a,b)=1 ∴gcd(a+b,a)=1,gcd(a+b,b)=1 ∴a+b|d 不妨设d=(a+b)t,那么我们求的就是三元组(a,b,t)的个数,其中满足a<b,gcd(a,b)=1,b(a+b)t≤N 那么如果我们的a和b确定了,满足要求的t显然有?Nb(a+b)?个 由于b≤?N

[BZOJ 1066] [SCOI2007] 蜥蜴 【最大流】

题目链接:BZOJ - 1066 题目分析 题目限制了高度为 x 的石柱最多可以有 x 只蜥蜴从上面跳起,那么就可以用网络流中的边的容量来限制.我们把每个石柱看作一个点,每个点拆成 i1, i2,从 i1 到 i2 连一条边,容量为这个石柱 i 的高度,即跳跃次数限制.来到这个石柱就是向 i1 连边,从这个石柱跳起就是从 i2 向外连边,这样只要从石柱 i 跳起就一定会消耗 i1 到 i2 的边的容量.如果 i 有蜥蜴,就从 S 到 i1 连一条容量为 1 的边,如果从石柱 i 能跳出边界,就从

bzoj 2301 Problem b - 莫比乌斯反演

Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Output 共n行,每行一个整数表示满足要求的数对(x,y)的个数 Sample Input 22 5 1 5 11 5 1 5 2 Sample Output 143 HINT 100%的数据满足:1≤n≤50000,1≤a≤b≤50000

【BZOJ】【2982】Combination

排列组合 Lucas定理模板题…… 感觉我做题顺序有点问题啊……应该是BZOJ 2982-->HDOJ 3037-->BZOJ 1272 好吧这个现在来看就有些水了…… 预处理一下fact和inv即可 1 /************************************************************** 2 Problem: 2982 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:4 ms 7 Mem