2022-03-12 11:37阅读: 69评论: 0推荐: 0

牛客寒假集训第六场 -牛妹的数学难题

牛妹的数学难题

思路

重点是理解连续求和的意义,以及注意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 中国大陆许可协议进行许可。

posted @   TimMCBen  阅读(69)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.