牛客寒假集训第六场 -牛妹的数学难题
牛妹的数学难题
思路
重点是理解连续求和的意义,以及注意ai的范围
如s(i=1,2)s(j=1,2)ai*aj,画出一个二维矩阵,分别对应(1,2),(2,2),(2,1),(1,1)三种情况,所以这里类似理解,相当于在n个数中取不同的k个数(看下标,各不相同),如果有0,贡献的答案一定是0,如果没有0仅1和2,则可以贡献正整数值。
设有a个1,b个2,若a+b<k一定会取到0,此时答案一定为0
当a+b>=k 则可以搞。a中取x个1,b中取k-x个y,然后2取幂,然后累加(注意这里k-x>=0,x<=a得到a的范围是<=min(a,k) )
注意:这里对x的限制也可以移到求组合数中间去,只要限制n>=m
用到的技巧
由于需要多次取快速幂,不如直接预处理所有的2的幂次。
组合数计算需要用到逆元,这里范围是1e7,若用费马小定理,必超时
所以采用线性求逆元的方法 两种都可
1.可以在求阶乘的时候直接求出 单个数 的逆元,然后 逆元阶乘
2.或者求出 前缀积 最后一个值的逆元,然后反过来求每个前缀积的逆元,就是组合数所需要用到的。
注意初始化 inv[ 0 ]=inv[ 1 ]=1.
#include<bits/stdc++.h> using namespace std; #define int long long int n,k; const int N = 1e7+5; const int mod=998244353; int f[N]; int fv[N]; int inv[N]; int p[N]; long long qpow(int a,int n) { long long base = 1; while(n) { if(n&1) { base=base*a%mod; } a=a*a%mod; n>>=1; } return base; } long long c(int n,int m) { if(n<m) return 0; return f[n]*inv[m]%mod*inv[n-m]%mod; } signed main() { f[0]=f[1]=1; inv[0]=inv[1]=1; for(int i=2;i<=N-1;i++) { f[i]=i; f[i]=f[i-1]*f[i]%mod; inv[i]=(mod-mod/i)*inv[mod%i]%mod; } // fv[N-1]=qpow(f[N-1],mod-2); // for(int i=N-1;i>=1;i--) // { // fv[i-1]=fv[i]*i%mod; // } for(int i=2;i<=N-1;i++) { inv[i]=inv[i-1]*inv[i]%mod; } p[0]=1; for(int i=1;i<=N-1;i++) { p[i]=p[i-1]*2%mod; } cin>>n>>k; int a=0,b=0; for(int i=1;i<=n;i++) { int num; cin>>num; if(num==1) a++; else if(num==2) b++; } // cout<<a<<" "<<b<<endl; // cout<<c(2,1)<<endl; if(a+b<k) { cout<<0; return 0; } long long ans=0; for(int i=0;i<=k;i++) { ans=(ans+c(a,i)*c(b,k-i)%mod*p[k-i]%mod)%mod; } cout<<ans; }
本文作者:TimMCBen
本文链接:https://www.cnblogs.com/TimMCBen/p/15996758.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步