牛妹的数学难题
思路
重点是理解连续求和的意义,以及注意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
当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
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=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<