【BZOJ 4517】【SDOI 2016 Round1 Day2 T2】排列计数
本蒟蒻第一次没看题解A的题竟然是省选Round1 Day2 T2 这道组合数学题。
考试时一开始以为是莫队,后来想到自己不会组合数的一些公式,便弃疗了去做第三题,,,
做完第三题后再回来看这道题,想到暴力算组合数×错排,我记得有一天晚上Snayvals问过我错排公式怎么推,但我并没有在意!!!幸亏我知道错排可以线性推出来,便开始用笔推错排公式。推了30min发现有计算机为什么不用!!!便打了一个表,很快就找出了规律f[i]=(f[i-1]*f[i-2])*(i-1)
然后开始解决组合数问题。因为组合数特别大要取模,可是我忘了拓展欧几里得的模板TwT,一个月前看了好长时间都没有理解,后来弃疗背过模板一直用着,结果长时间不写就忘了QAQ。然后辛苦的回忆zky学长讲课时拓展欧几里得是怎么做的,想了一个小时终于通过普通的欧几里得回忆起了拓展欧几里得怎么做,以后再也不会忘了QuQ。
可以求逆元,可以线性时间求出错排数和阶乘,然后求出逆元的“前缀积”,O(5nlogn)时间内可以求出最大数据内的所有需要的值,离线一下就可以预处理后O(1)回答询问啦,就可以A啦~~~最后A掉了这道题,虽然是道水题,但是作为没看题解AC的第一道题心里还是有点激动。
PS:在BZOJ上凑个热闹233
省选时的AC代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=getint() using namespace std; const int p = 1E9 + 7; int getint() { int k = 0, fh = 1; char c = getchar (); for (; c < '0' || c > '9' ; c = getchar ()) if (c == '-' ) fh = -1; for (; c >= '0' && c <= '9' ; c = getchar ()) k = k * 10 + c - '0' ; return k * fh; } long long f[1000003], ni[1000003], nic[1000003], jc[1000003]; void mktb( int n) { f[0] = 1; f[1] = 0; f[2] = 1; for ( int i = 3; i <= n; ++i) f[i] = (((f[i - 1] + f[i - 2])%p) * (i - 1)) % p; jc[1] = 1; for ( int i = 2; i <= n; ++i) jc[i] = (jc[i - 1] * i) % p; } void exgcd( int a, int b, long long &x, long long &y) { if (b == 0) { x = 1; y = 0; } else { exgcd(b, a % b, x, y); long long t = x; x = y; y = t - a / b * y; } } void mkny( int n) { long long x, y; ni[1] = 1; for ( int i = 2; i <= n; ++i) { exgcd(i, p, x, y); ni[i] = x < 0 ? x + p : x; } nic[0] = 1; nic[1] = 1; for ( int i = 2; i <= n; ++i) nic[i] = (nic[i - 1] * ni[i]) % p; } struct node { int n, m; } q[500003]; int upe = 0; long long Q( int n, int m) { if (n < m) return 0; long long ans = (jc[n] * nic[m]) % p; ans = (ans * nic[n - m]) % p; ans = (ans * f[n - m]) % p; return ans; } int main() { freopen ( "permutation.in" , "r" , stdin); freopen ( "permutation.out" , "w" , stdout); int T; read(T); for ( int i = 1; i <= T; ++i) { read(q[i].n); read(q[i].m); if (q[i].n > upe) upe = q[i].n; } mktb(upe); mkny(upe); for ( int i = 1; i <= T; ++i) printf ( "%I64d\n" , Q(q[i].n, q[i].m)); fclose (stdin); fclose (stdout); return 0; } |
啦啦啦
NOI 2017 Bless All
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从零实现富文本编辑器#3-基于Delta的线性数据结构模型
· 记一次 .NET某旅行社酒店管理系统 卡死分析
· 长文讲解 MCP 和案例实战
· Hangfire Redis 实现秒级定时任务,使用 CQRS 实现动态执行代码
· Android编译时动态插入代码原理与实践
· 使用TypeScript开发微信小程序(云开发)-入门篇
· 没几个人需要了解的JDK知识,我却花了3天时间研究
· 定时任务稳定性解决方案-healthchecks监控系统
· 在SqlSugar的开发框架中增加对低代码EAV模型(实体-属性-值)的WebAPI实现支持
· .NET Core中的配置Configuration实战