或许更好的阅读体验/题目传送门
前置芝士
- 二项式定理:(a+b)n=i=0∑nCni×ai×bn−i
- 快速幂
Meaning
有 n 种珠子,每种有 ai 颗,且美丽值为 vi。任意两颗珠子不同(同种类也算不同)。每种珠子有一个漂亮值 vi。项链有一个美丽度,若第 i 种珠子在项链中有 cnt 颗并且 cnt≥1,则这串项链的美丽度会加上 (vi)cnt。求所有不同的项链的美丽度总和是多少。
Solution
以下记 S=i=1∑nai,且以下式子默认对 109+7 取模。
subtask 1
留给搜索。
每一颗珠子枚举是否选择,即有 2S 种项链。枚举一下就行。
时间复杂度 O(2S)。
subtask 2
开始推式子。
对于第 i 种珠子,剩下 S−ai 颗珠子,有 2S−ai 种取法。而在这 i 颗珠子中,取 x 颗,美丽值增加 (vi)x。取 x 颗珠子的方案数为 Caix。所以答案为:
i=1∑nx=1∑ai(2S−ai×Caix×vix)=i=1∑n[2S−ai×x=1∑ai(Caix×vix)]
时间复杂度 O(SlogS)。其中 logS 是快速幂的时间复杂度。
subtask 3
显然,subtask 2 的时间复杂度会 T 飞。
外面一层明显无法化简,此时回头看一眼二项式定理:
(a+b)n=i=0∑nCni×ai×bn−i
再看看里面那一坨式子:
x=1∑ai(Caix×vix)
稍微变下形:
x=1∑ai(Caix×vix×1ai−x)
这两个好像!
所以答案可以变为 i=1∑n[2S−ai×(vi+1)ai]?
由于原式中是从 1 开始遍历的,所以还需要减去 Cai0×vi0×1ai=1。
故答案为 i=1∑n{2S−ai×[(vi+1)ai−1]}
时间复杂度 O(nlogS)。
code
杜绝复制!
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[2000003],v[2000003];
int qpow(int a,int n,int mod)
{
int re=1;
while(n)
{
if(n&1)
re=(re*a)% mod;
n>>=1;
a=(a*a)%mod;
}
return re%mod;
}
signed main()
{
int n,ans=0,s=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],s+=a[i];
for(int i=1;i<=n;i++) cin>>v[i];
for(int i=1;i<=n;i++)
{
int cnt=0;
cnt=qpow(v[i]+1,a[i],1000000007)-1;
ans+=cnt*qpow(2,s-a[i],1000000007),ans%=1000000007;
}
cout<<ans;
return 0;
}