暑假集训第二弹

A:不会做 // 留坑

 

———————————————————分————割————线———————————————————

 

B:CodeForces 577C Vasya and Petya's Game
传送门:http://acm.hust.edu.cn/vjudge/problem/241498/origin
题意:给一个数n 问你在[1,n]的区间内 有一个数m 你要猜哪几个数以后就肯定能得出答案。

   你猜一个数x 会回答你 x是否能整除m

输入:一个n

输出:你要猜的那些数

 

思路:

  从小往大猜,把倍数都标记一边,最后只被标记1次就是你需要猜的数

 

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int ans[1010],a[1010],tot=0;

int main()
{
    memset(a,0,sizeof a);
    int n;
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
        if(!a[i])
            for(int j=i;j<=n;j=j+i)
                a[j]++;
    for(int i=2;i<=n;i++)
        if(a[i]<2)
            ans[tot++]=i;
    printf("%d\n",tot);
    for(int i=0;i<tot;i++)
        printf("%d ",ans[i]);
    printf("\n");
} 
View Code

 


———————————————————分————割————线———————————————————

 

C:POJ 2407 Relatives
传送门:http://poj.org/problem?id=2407
题意:给你一个n 问你有几个小于n的且与n互质的个数

输入:n

输出:个数

思路:欧拉函数

 

代码:

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

long long eular(long long n)
{
    long long ans=n;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            ans -= ans/i;
            while(n%i==0)
                n /= i;
        }
    }
    if(n>1)    ans -= ans/n;
    return ans;
}

int main()
{
    long long n;
    while(~scanf("%lld",&n) && n)
        printf("%lld\n",eular(n));
} 
View Code

 


———————————————————分————割————线———————————————————

 

D:CodeForces 630B Moore's Law     (水)
传送门:http://codeforces.com/problemset/problem/630/B


题意:给你2个数 a,b 问你 a*1.000000011^b

输入:两个数

输出:1个答案

思路:快速幂(然而直接pow也是能过的)

此处无代码

 


———————————————————分————割————线———————————————————

 

E:CodeForces 630F     Selection of Personnel

传送门:http://codeforces.com/problemset/problem/630/F

题意:给你一个数n 要你求出C(5,n)C(6,n),C(7,n)

输入:一个数

输出:答案

思路:就是组合数  因为容易乘爆 所以要乘一个数除一个数

 

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int main()
{
    int n;
    scanf("%d",&n);
    long long ans=0;
    for(int i=5;i<=7;i++)
    {
        long long now=1;
        for(int j=1;j<=i;j++)
            now=now*(n-j+1)/j;
        ans += now;
    }
    printf("%lld",ans);
} 
View Code

 

———————————————————分————割————线———————————————————

 

F:CodeForces 630G   Challenge Pennants

传送门:http://codeforces.com/problemset/problem/630/G

题意:公司有5面A锦旗,3面B锦旗,先欲将这些锦旗全部发给n位员工,每位员工可以得到任意种类任意数量的锦旗,问有多少种发放方案 

输入:员工数

输出:方案数

 

思路: 

  组合数问题 假设A锦旗放到1个人 2个人...5个人分别有 1 4 6 4 1的放法 然后乘上C(i,n)在求和

同理算出B锦旗的方法相乘

 

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int a[5]={1,4,6,4,1};
int b[3]={1,2,1};

long long C(long long n,long long m)
{
    if(n>m-n)
        n=m-n;
    long long ans=1;
    for(int i=1;i<=n;i++)
        ans = ans*(m-i+1)/i;
    return ans;
}

int main()
{
    int n;
    scanf("%d",&n);
    long long ans1=0,ans2=0;
    for(int i=0;i<5;i++)
    {
        if(i+1<=n)
            ans1 += C(i+1,n)*a[i];
        else
            break;
    }
    for(int i=0;i<3;i++)
    {
        if(i+1<=n)
            ans2 += C(i+1,n)*b[i];
        else
            break;
    }
    printf("%lld",ans1*ans2);
} 
View Code

 

———————————————————分————割————线———————————————————

 

G:CodeForces 630K  Indivisibility

传送门:http://codeforces.com/problemset/problem/630/K

题意:给你一个数n,问你[1,n]中有多少个数不能被 2~10整除

输入:一个数

输出:答案

 

思路:
  因为4 6 8 6 9 是2 3 的倍数 所以2~10相当于 2 3 5 7

 

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int main()
{
    long long n,now=0;
    scanf("%lld",&n);
    now += n/2+n/3+n/5+n/7;
    now -= n/6+n/10+n/14+n/15+n/21+n/35;
    now += n/30+n/42+n/70+n/105;
    now -= n/210;
    printf("%lld",n-now);
} 
View Code

 

———————————————————分————割————线———————————————————

 

H题题目有错 跳过

 

———————————————————分————割————线———————————————————

 

I:POJ 2480  Longge's problem

传送门:http://poj.org/problem?id=2480

题意:给你1个数n 问你gcd(i, N) 1<=i <=N  的和是多少

思路:

  这里是看了dalao们的题解才理解的// 需要注意的是sqrt枚举才行 i*i会T

  dalao传送门:http://www.cnblogs.com/flipped/p/5690123.html

  欧拉函数 φ(x)φ(x) :1到x-1有几个和x互质的数。

  gcd(i,n)必定是n的一个约数。

  若p是n的约数,那么gcd(i,n)==p的有φ(n/p)φ(n/p)个数,因为要使gcd(i,n)==p,i/p和n/p必须是互质的。

  那么就是求i/p和n/p互质的i在[1,n]里有几个,就等价于 1/p,2/p,...,n/p 里面有几个和n/p互质,即φ(n/p)。

  求和的话,约数为p的有φ(n/p),所以就是p*φ(n/p),同时把约数为n/p的加上去,i*i==n特判一下。

 

代码:

    

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
using namespace std;

typedef long long LL;

LL phi(LL n)
{
    LL res=n;
    for(int i=2;i<=sqrt(n);i++)
    {
        if(n%i==0)
        {
            res=res/i*(i-1);
            while(n%i==0) n/=i;
        }
    }
    if(n>1)
        res=res/n*(n-1);
    return res;
}

int main()
{
    LL n;
    while(~scanf("%lld",&n))
    {
        LL ans=0;
        for(int i=1;i<=sqrt(n);i++)
        {
            if(i*i==n)
                ans += i*phi(n/i);
            else if(n%i==0)
                ans += i*phi(n/i)+(n/i)*phi(i);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

———————————————————分————割————线———————————————————

 

J:HDU 5698  瞬间移动

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5698

题意:中文题

思路:

  点从(1,1)移动到(m,n)最少要移动的步数为 min(m-1,n-1)

  然后枚举几步走完全过程时横着的情况*竖着的情况

  特例就是1步到位 答案为1 可以C(m-2,0)得到1

  然后组合数求逆元就行了

ps:

  网上有个证明把答案化为


C(m+n4,n+2)=(n+m4)!(n2)!(m2)!

 

代码;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100100
#define M 1000000007
typedef long long ll;

ll A[N],B[N];

ll powinv(ll a, ll b)                // 快速幂求乘法逆元 
{
    ll ans = 1;
    a = a % M;
    while(b)
    {
        if(b & 1) ans = ans * a % M;
        a = a * a % M;
        b >>= 1;
    }
    return ans;
}

ll C(ll m,ll n)
{
    return (A[m] * B[n]%M * B[m-n]%M) % M;
}

int main()
{
    A[0]=1;
    for(int i=1;i<N;i++) 
        A[i]=A[i - 1]*i % M;
        
    B[N-1] = powinv(A[N-1],M-2);            
    for(int i=N-1;i>=1;i--) 
        B[i-1]=B[i]*i % M;
        
    ll m,n;
    while(~scanf("%lld %lld",&m,&n))
    {
        ll ans=0;
        for(int i=1;i<min(m,n);i++)
        ans += C(n-2,i-1)*C(m-2,i-1)%M;
    
        printf("%lld\n",ans%M);
    }

} 
View Code

 

———————————————————分————割————线———————————————————

 

K:HDU 3037       Saving Beans

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3037

题意:求在n棵树上摘不超过m颗豆子的方案,结果对p取模。

思路:求C(n+m,m)%p  数据很大用Lucas定理 

 

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

ll f[100010];

void init(ll p)
{
    f[0]=1;
    for(int i=1;i<=p;i++)
        f[i]=(f[i-1]*i)%p;
}

ll powinv(ll a, ll b, ll M)                // 快速幂求乘法逆元 
{
    ll ans = 1;
    a = a % M;
    while(b)
    {
        if(b & 1) ans = ans * a % M;
        a = a * a % M;
        b >>= 1;
    }
    return ans;
}

ll Lucas(ll n, ll m, ll p)
{
    ll ans = 1;
    while (n && m)
    {
        ll nn = n%p, mm = m%p;
        if (nn < mm) return 0;    
        ans = ans * f[nn] * powinv(f[mm]*f[nn-mm]%p, p-2, p)%p;
        n /= p;
        m /= p;
    }
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {    
        ll a,b,p;
        scanf("%lld %lld %lld",&a,&b,&p);
        init(p);
        printf("%lld\n",Lucas(a+b,b,p));
    }
}
View Code

 

posted @ 2016-07-28 11:42  后知后觉丶  阅读(174)  评论(0编辑  收藏  举报