E - Card Collector
题意:
每包里面最多只有一张卡片(可能没有),要集齐n张不同的卡片(1<=n<=20)
问集齐
n
n
n张卡片要买的包数期望
题解:
设集齐第
i
i
i张的天数需要
d
i
di
di天
求解买
n
n
n张卡片需要的包数:
d
1
U
d
2
U
d
3...
U
d
n
d1 U d2 U d3 ... U dn
d1Ud2Ud3...Udn-
1
1
1,所以容斥公式求解
概率和期望:(可由无穷级数得证)
如果一件事发生的概率为
p
i
pi
pi,那么第一次发生这件事次数期望为
1
/
p
i
1/pi
1/pi。
同理,a和b这两件事发生的概率为
p
1
,
p
2
p1,p2
p1,p2,则第一次发生某一件事发生的次数期望为
1
/
(
p
1
+
p
2
)
1/(p1+p2)
1/(p1+p2)
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
const int MAXN = 3e5;
const int N = 22;
double p[N];
double dp[1<<N];
int n,cnt;
double IEP()
{
double sum=0;
for(int i=1;i<(1<<cnt);i++)///容斥原理
{
double f=-1,ans=0;
for(int j=0;j<cnt;j++)///枚举每种质因数的组合
{
if(i&(1<<j))
{
ans+=p[j];
f=f*(-1);
}
}
sum=sum+(1.0/ans)*f;///(x/ans)表示:1-x中有ans因数的个数
}
return sum;
}
int main()
{
while(~scanf("%d", &n))
{
for(int i = 0; i < n; i ++)
scanf("%lf", &p[i]);
double ans = 0.0;
cnt=n;
ans=IEP();
printf("%.5lf\n", ans);
}
}
F - Visible Trees
题意:
有许多树组成一个
m
∗
n
m * n
m∗n网格,网格从
(
1
,
1
)
(1,1)
(1,1)开始。农夫夏洛克站在
(
0
,
0
)
(0,0)
(0,0)点。他想知道他能看到多少棵树。如果两棵树和夏洛克站在一条线上,农民夏洛克只能看到离他最近的那棵树。
题解:
求解1到m和1到n有多少对互质的数,分解
m
i
n
(
n
,
m
)
min(n,m)
min(n,m)的一个数,然后容斥求解互质即可
#include<cstdio>
#include<algorithm>
#define mp make_pair
#define maxn 10000000
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
const int N=1e6+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=998244353 ;
ll n,m,x,y,k,cnt,t;
ll prime[N];
void gets(ll x)
{
ll s=sqrt(x);
cnt=0;
for(int i=2;i<=s;i++)
{
if(x%i==0)
prime[cnt++]=i;
while(x%i==0)
x=x/i;
}
if(x!=1)
prime[cnt++]=x;
}
ll IEP(ll x)
{
if(x<0) return 0;
ll sum=0;
for(int i=1;i<(1<<cnt);i++)///容斥原理
{
ll f=-1,ans=1;
for(int j=0;j<cnt;j++)///枚举每种质因数的组合
{
if(i&(1<<j))
{
ans=ans*prime[j];
f=f*(-1);
}
}
sum=sum+(x/ans)*f;///(x/ans)表示:1-x中有ans因数的个数
}
return x-sum;
}
int main()
{
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
scanf("%lld",&t);
while(t--)
{
scanf("%d%d",&n,&m);
if(n>m) swap(n,m);
ll ans=0;
for(int i=1;i<=n;i++)
{
gets(i);
ans+=IEP(m);
}
printf("%lld\n",ans);
}
}
G - How many integers can you find
题意:
现在你得到一个
N
,
M
−
i
n
t
e
g
e
r
s
N, M-integers
N,M−integers集,你应该找出多少整数比
N
N
N,小,他们可以任何整数整除的。例如,
N
N
N =
12
12
12,和
M
−
i
n
t
e
g
e
M-intege
M−integer{
2
,
3
2,3
2,3},所以有另一组{
2
,
3
,
4
,
6
,
8
,
9
,
10
2,3,4,6,8,9,10
2,3,4,6,8,9,10},的所有整数集可以被
2
2
2或
3
3
3整除。因此,您只需输出数字
7
7
7。
题解:容斥
注意:因为是整除注意特判
0
0
0,以及M集合可能有重复的元素,所以当进行容斥的时候注意将选中的因子取最小公倍数,避免重复。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define mp make_pair
#define maxn 10000000
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
const int N=1e6+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=998244353 ;
ll n,m,x,y,k,cnt,t;
ll prime[N];
ll lcm(ll m,ll n)
{
return m/__gcd(m,n)*n;
}
ll IEP(ll x)
{
ll sum=0;
for(int i=1;i<(1<<cnt);i++)///容斥原理
{
ll f=-1,ans=1;
for(int j=0;j<cnt;j++)///枚举每种质因数的组合
{
if(i&(1<<j))
{
ans=lcm(ans,prime[j]);
f=f*(-1);
}
}
sum=sum+(x/ans)*f;///(x/ans)表示:1-x中有ans因数的个数
}
return sum;
}
int main()
{
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
while(~scanf("%lld%lld",&n,&m))
{
cnt=0;
for(int i=0;i<m;i++)
{
scanf("%lld",&x);
if(x!=0) prime[cnt++]=x;
}
printf("%lld\n",IEP(n-1));
}
}
题意:
求
F
(
x
)
F(x)
F(x) =
(
1
+
x
)
a
1
(1+x)^{a_{1}}
(1+x)a1 +
(
1
+
x
)
a
2
(1+x)^{a_{2}}
(1+x)a2+ … +
(
1
+
x
)
a
m
(1+x)^{a_{m}}
(1+x)am.中系数为奇数的项的个数
题解:
性质一:由
L
u
c
a
s
Lucas
Lucas定理可知,
(
1
+
x
)
n
(1+x)^n
(1+x)n 中奇数项的个数等于
2
(
n
的
二
进
制
表
示
中
1
的
个
数
)
2^{(n的二进制表示中1的个数)}
2(n的二进制表示中1的个数).
性质二:
(
1
+
x
)
n
(1 + x) ^ n
(1+x)n中的系数中 所有奇系数之和等于偶系数之和等于
2
(
n
−
1
)
2^{(n-1)}
2(n−1)
性质三:两个集合的交: 比如系数
w
1
,
w
2
,
p
o
s
=
w
1
w_1,w_2,pos=w_1
w1,w2,pos=w1&
w
2
w_2
w2集合的交的个数是
2
p
o
s
的
二
进
制
里
1
的
个
数
2^{pos的二进制里1的个数}
2pos的二进制里1的个数
嗯这个
L
u
c
a
s
Lucas
Lucas定理的证明,没看懂,反正是这么个东西。
参考题解:
集合
A
,
B
,
C
A,B,C
A,B,C表示不同次幂下,奇数系数项的个数
n
u
m
(
A
∪
B
∪
C
)
num(A∪B∪C)
num(A∪B∪C)表示合并后一共有多少个不同的奇数系数项,这里的奇数系数指的合并前的。
举例来说:
(
1
+
x
)
1
(1 + x) ^ 1
(1+x)1奇数项有 2项,
(
1
+
x
)
2
(1 + x) ^ 2
(1+x)2奇数项有 2项,
(
1
+
x
)
3
(1 + x) ^ 3
(1+x)3奇数项有 4项
因此
n
u
m
(
A
∪
B
∪
C
)
num(A∪B∪C)
num(A∪B∪C)的值有4项。
当 集合合并偶数次的时候,相同次幂的奇数系数项自然变成偶数所以要减去,但是会多减,如下图的 10区域,所以还得加回来。
因此:
F
(
x
)
F(x)
F(x)中奇数系数项的个数=
n
u
m
(
A
∪
B
∪
C
)
num(A∪B∪C)
num(A∪B∪C)-
n
u
m
(
A
∩
B
)
num(A∩B)
num(A∩B)-
n
u
m
(
A
∩
C
)
num(A∩C)
num(A∩C)-
n
u
m
(
B
∩
C
)
num(B∩C)
num(B∩C)+
3
∗
n
u
m
(
A
∩
B
∩
C
)
3*num(A∩B∩C)
3∗num(A∩B∩C)
进一步化简:
F
(
x
)
F(x)
F(x)中奇数系数项的个数=
n
u
m
(
A
)
+
n
u
m
(
B
)
+
n
u
m
(
C
)
−
2
∗
n
u
m
(
A
∩
B
)
−
2
∗
n
u
m
(
A
∩
C
)
−
2
∗
n
u
m
(
B
∩
C
)
+
4
∗
n
u
m
(
A
∩
B
∩
C
)
num(A)+num(B)+num(C) -2*num(A∩B)-2*num(A∩C)-2*num(B∩C) +4*num(A∩B∩C)
num(A)+num(B)+num(C)−2∗num(A∩B)−2∗num(A∩C)−2∗num(B∩C)+4∗num(A∩B∩C)
#include<cstdio>
#include<algorithm>
#include<cmath>
#define mp make_pair
#define maxn 10000000
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
const int N=1e6+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=998244353 ;
ll n,m,x,y,k,cnt,t,ans;
ll a[N];
ll get (ll x)
{//计算x的二级制位有多少个1
return x==0?0:get(x-(x&-x))+1; //(x&-x)是取出最低位的1
}
void dfs(ll pos,ll num,ll fla)
{
ans+=(1ll<<get(num))*fla;//需要强制类型转换,精度
for(ll i=pos+1;i<=n;i++)
dfs(i,num&a[i],-2*fla);
}
int main()
{
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
scanf("%lld",&t);
k=t;
while(t--)
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
ans=0;
for(int i=1;i<=n;i++)//全排列
dfs(i,a[i],1);
printf("Case #%lld: %lld\n",k-t,ans);
}
}