证明:
我们考虑集合中的每个数对答案的贡献(不可重集),然后显然
应用:
[HAOI2015]按位或
#include
using namespace std;
const double eps=1e-3;
const int N=20;
double a[1<<N],ans;
int n;
int get_sum(int x){
int ans=0;
while (x) ans+=(x&1),x>>=1;
return (ans+1)&1;
}
int main(){
scanf("%d",&n);
for (int i=0;i<(1<<n);i++) scanf("%lf",&a[i]);
for (int i=0;i<n;i++)
for (int j=0;j<(1<<n);j++) if ((1<<i)&j) a[j]+=a[j^(1<<i)];
int len=(1<<n)-1;
for (int i=1;i<(1<<n);i++)
if (fabs(1.0-a[i^len])>eps) if (get_sum(i)) ans=(ans-1.0/(1.0-a[i^len])); else ans+=1.0/(1.0-a[i^len]);
else {puts("INF"); return 0;}
printf("%.10lf\n",ans);
}
51nod1355 斐波那契的最小公倍数
在斐波那契数列中有个结论
g c d ( F a , F b ) = F g c d ( a , b ) gcd(F_{a},F_{b})=F_{gcd(a,b)} gcd(Fa,Fb)=Fgcd(a,b)
证明略
但是本题让我们求lcm
这就启发我们思考lcm与gcd直接的关系
但是直接想好像没有什么发现
我们把每个数抽象成一个由质数为基础的向量空间
我们发现对于lcm就是每个质数维度求max,对于gcd就是每个质数维度求min
我们考虑min-max容斥
l c m ( F { S } ) = ∏ T ⊆ S g c d ( F { T } ) ( − 1 ) ∣ T ∣ + 1 = ∏ T ⊆ S F g c d { T } ( − 1 ) ∣ T ∣ + 1 lcm(F_{\left\{S\right\}})=\prod_{T\subseteq S}gcd(F_{\left\{T\right\}})^{(-1)^{|T|+1}}=\prod_{T\subseteq S}{F_{gcd\left\{T\right\}}}^{(-1)^{|T|+1}} lcm(F{S})=∏T⊆Sgcd(F{T})(−1)∣T∣+1=∏T⊆SFgcd{T}(−1)∣T∣+1
利用上述知识似乎到这一步就止了,我们需要更为强力的武器
g c d { T } ? gcd\left\{T\right\}? gcd{T}?莫比乌斯反演?
给个不那么严谨的做法,我们定义 g i g_{i} gi为gcd为i及其倍数的质数所产生的贡献,然后直接容斥
#include
#define ll long long
using namespace std;
const int N=1e6+10;
const int mod=1e9+7;
int a[N],g[N],f[N];
int n,x;
ll ksm(ll x,ll y){
ll ans=1;
for (;y;y>>=1,x=(x*x)%mod) if (y&1) ans=(ans*x)%mod;
return ans;
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&x),a[x]++;
f[0]=0; f[1]=1;
for (int i=2;i<N;i++) f[i]=(f[i-1]+f[i-2])%mod;
for (int i=1;i<N;i++) {
int sum=0;
for (int j=1;j*i<N;j++) sum+=a[j*i];
if (sum) g[i]=1;
}
for (int i=N-1;i>=1;i--)
for (int j=2;j*i<N;j++) g[i]-=g[i*j];
ll ans=1;
for (int i=1;i<N;i++) if (g[i]!=0) {
if (g[i]>0) ans=ans*ksm(f[i],g[i])%mod;
else ans=ans*ksm(ksm(f[i],-g[i]),mod-2)%mod;
}
printf("%lld\n",ans);
}
我们考虑 k − t h M a x ( S ) = ∑ T ⊆ S f ( ∣ T ∣ ) m i n ( T ) k-thMax(S)=\sum_{T\subseteq S}f(|T|)min(T) k−thMax(S)=∑T⊆Sf(∣T∣)min(T)
我们每个数被算到的贡献,不妨假设为第x大的数,总共有n个元素
其贡献为 ∑ i = 0 x − 1 C ( x − 1 , i ) f ( i + 1 ) \sum_{i=0}^{x-1}C(x-1,i)f(i+1) ∑i=0x−1C(x−1,i)f(i+1),根据要求 [ x = = k ] = ∑ i = 0 x − 1 C ( x − 1 , i ) f ( i + 1 ) [x==k]=\sum_{i=0}^{x-1}C(x-1,i)f(i+1) [x==k]=∑i=0x−1C(x−1,i)f(i+1)
直接上二项式反演
f ( i ) = C ( i − 1 , k − 1 ) ( − 1 ) i − k f(i)=C(i-1,k-1)(-1)^{i-k} f(i)=C(i−1,k−1)(−1)i−k
k − t h M a x ( S ) = ∑ T ⊆ S C ( ∣ T ∣ − 1 , k − 1 ) ( − 1 ) ∣ T ∣ − k m i n ( T ) k-thMax(S)=\sum_{T\subseteq S}C(|T|-1,k-1)(-1)^{|T|-k}min(T) k−thMax(S)=∑T⊆SC(∣T∣−1,k−1)(−1)∣T∣−kmin(T)
对于期望依然成立
重返现世
#include
#define ll long long
using namespace std;
const int mod=998244353;
const int D=13;
const int N=1010;
const int M=10010;
int dp[D][M],p[N],inv[M];
int n,k,m;
int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
int mul(int x,int y){return (ll)x*y%mod;}
int ksm(int x,int y){
int ans=1;
for (;y;y>>=1,x=mul(x,x)) if (y&1) ans=mul(ans,x);
return ans;
}
void init(){
inv[0]=inv[1]=1;
for (int i=2;i<M;i++) inv[i]=mul(mod-mod/i,inv[mod%i]);
}
int main(){
scanf("%d%d%d",&n,&k,&m);
k=n-k+1;
for (int i=1;i<=n;i++) scanf("%d",&p[i]);
init();
dp[0][0]=1;
for (int i=1;i<=n;i++) {
for (int j=k;j>=1;j--)
for (int q=m;q>=p[i];q--)
dp[j][q]=add(dp[j][q],dec(dp[j-1][q-p[i]],dp[j][q-p[i]]));
}
int ans=0;
for (int i=0;i<=m;i++) ans=add(ans,mul(inv[i],dp[k][i]));
printf("%d\n",mul(ans,m));
}