这个半周其实挺时间紧张的一大波期末考试即将来到,但我还是坚持推进着系统学习组合数学。另外还有一个原因,题目里有一些关于数学期望的东西,样例求的值有些懵,了解了一点概率的东西才有开始做。整理一下重点题目吧。
O题(GCD ):求a<=x<=b,c<=y<=d(其中a,c题目中已经说了必为1),中有多少对(x,y)满足GCD(x,y)=k。
因为gcd(x/k,y/k)=1,由此可以转化成求两区间[1,b/k]和[1,d/k]中各选一个数两数互质的数有多少对组合。假设b<=d,那么分为两部分 1,当[1,b]与[1,b]间是就是求欧拉函数phi[1]+phi[2]+...phi[b]。2,求[1,b]与[b+1,d],求此区间有多少对数互质,可以先求出有多少对数不互质,再用b减去。这就可以用容斥原理解决了。
void getprime()//线性筛出素数和欧拉函数
{
int k=0;
memset(is,false,sizeof(is));
phi[1]=1;
for(int i=2;i<100005;i++)
{
if(is[i]==false)
{
phi[i]=i-1;
prime[k++]=i;
}
for(int j=0;j<k&&i*prime[j]<100005;j++)
{
is[i*prime[j]]=true;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
{
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
}
void solve()//分解因子
{
for(int i=1;i<=100000;i++)
{
int k=i;
for(int j=0;prime[j]*prime[j]<=k;j++)
{
if(k%prime[j]==0)
{
q[i].push_back(prime[j]);
while(k%prime[j]==0) k/=prime[j];
}
if(k==1) break;
}
if(k>1) q[i].push_back(k);
}
}
ll dfs(int a,int b,int it)//容斥原理...q[]是分解出的因子
{
ll ans=0;
for(int i=a;i<q[it].size();i++)
{
ll k=b/q[it][i];
ans=ans+k-dfs(i+1,k,it);
}
return ans;
}
L题(Card Collector ):在每包小当家方便面里面,可能有一张卡片,也可能没有。已知有总共有n张卡片,第i张的卡片出现的可能是pi。 问收集齐所有的卡片需要吃方便面数的期望是多少。
概率上说,假如买第种中卡片的几率是0.1,那么买10包必能中一包,那么已知一个事件在某个活动里发生的概率为p,则这个事件第一次发生需要的活动期望数为1/p,那么ans = 1/p1 + 1/p2 + .. + 1/pn - 1/(p1+p2) - 1/(p1+p3) - ... + 1/(p1+p2+p3) ... 这就又是容斥原理解决了。隐约感觉概率这门课,很神奇。。
N题(瞬间移动):有一个无限大的矩形,初始时你在左上角(即第一行第一列),每次你都可以选择一个右下方格子,并瞬移过去(如从下图中的红色格子能直接瞬移到蓝色格子),求到第nn行第mm列的格子有几种方案,答案对1000000007取模。
这个题其实退一下就发现f[i][j]=f[i-1][j]+f[i][j-1],不难发现是杨辉三角,利用其性质,第n行的m个数可表示为 C(n-1,m-1),即为从n-1个不同元素中取m-1个元素的组合数。 于是本题就转化为求C(n+m-4,m-2)%p。然后用费马小定理和卢斯卡定理求出就可以了。这里还要感谢费老师推荐的博客http://blog.csdn.net/Cai_Haiq/article/details/75954298