题目链接:http://acdream.info/problem?pid=1084
寒假安排
Time Limit: 2000/1000MS (Java/Others)
Memory Limit: 128000/64000KB (Java/Others)
Problem Description
寒假又快要到了,不过对于lzx来说,头疼的事又来了,因为众多的后宫都指望着能和lzx约会呢,lzx得安排好计划才行。
假设lzx的后宫团有n个人,寒假共有m天,而每天只能跟一位后宫MM约会,并且由于后宫数量太过庞大了,而寒假的天数太少,所以lzx在寒假里不会与一个MM约会一次以上。现在lzx想要知道:寒假安排的方案数如果写成k进制,末位会有多少个0。
Input
输入的第一行是一个整数,为数据的组数t(t<=1000)。
每组数据占一行,为3个正整数n、m和k(1<=m<=n<2^31,2<=k<2^31),意思如上文所述。
Output
对于每组数据,输出一个数,为寒假安排的方案数写成k进制末位的0的数目。
Sample Input
3 10 5 10 10 1 2 10 2 8
Sample Output
1 1 0
求n!中v因子个数的做法:
ll go(ll x, ll v){
ll ans = 0;
ll tmp = v;
while(x>=tmp){
ans += x/tmp;
tmp*=v;
}
return ans;
}
用n-m+1~n中质因数的个数除以k质因数的个数,既为化为二进制后末尾0的个数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
//x阶乘质因子v的个数
long long go(long long x, long long v)
{
long long ans = 0;
long long tmp = v;
while(x >= tmp)
{
ans += x/tmp;
tmp*=v;
}
return ans;
}
int main()
{
int cases;
cin>>cases;
long long a[10000];
long long tmp[10000];
long long cnt[10000];
long long n,m,k;
while(cases--)
{
long long top = 0;
long long ans=0;
memset(tmp,0,sizeof(tmp));
memset(cnt,0,sizeof(cnt));
cin>>n>>m>>k;
int kaifang =sqrt(k);
for(long long i = 2 ; i<=kaifang; i++)
{
if(k%i==0)
{
while(k%i==0)
{
cnt[top]++;
k/=i;
}
a[top++]=i;
//printf("i==%d\n",i);
}
}
if(k>1)
{
cnt[top]++;
a[top++]=k;
}
for(long long i = 0; i<top; i++)
tmp[i]+=go(n,a[i]);
for(long long i=0; i<top; i++)
tmp[i]-=go(n-m,a[i]);
ans=tmp[0]/cnt[0];
for(long long i=0; i<top; i++)
{
ans= ans<(tmp[i]/cnt[i])? ans:(tmp[i]/cnt[i]);
}
cout<<ans<<endl;
}
return 0;
}