zoukankan      html  css  js  c++  java
  • P2231 [HNOI2002]跳蚤

    题目描述

    Z城市居住着很多只跳蚤。在Z城市周六生活频道有一个娱乐节目。一只跳蚤将被请上一个高空钢丝的正中央。钢丝很长,可以看作是无限长。节目主持人会给该跳蚤发一张卡片。卡片上写有N+1个自然数。其中最后一个是M,而前N个数都不超过M,卡片上允许有相同的数字。跳蚤每次可以从卡片上任意选择一个自然数S,然后向左,或向右跳S个单位长度。而他最终的任务是跳到距离他左边一个单位长度的地方,并捡起位于那里的礼物。

    比如当N=2,M=18时,持有卡片(10, 15, 18)的跳蚤,就可以完成任务:他可以先向左跳10个单位长度,然后再连向左跳3次,每次15个单位长度,最后再向右连跳3次,每次18个单位长度。而持有卡片(12, 15, 18)的跳蚤,则怎么也不可能跳到距他左边一个单位长度的地方。

    当确定N和M后,显然一共有MN张不同的卡片。现在的问题是,在这所有的卡片中,有多少张可以完成任务。

    输入输出格式

    输入格式:

     

    输入文件有且仅有一行,包括用空格分开的两个整数N和M。

     

    输出格式:

     

    输出文件有且仅有一行,即可以完成任务的卡片数。

    1le Nle Mle 10^81NM108,且M^Nle 10^{16}MN1016。

     

    输入输出样例

    输入样例#1: 
    2 4
    输出样例#1: 
    12

    说明

    这12张卡片分别是:

    (1, 1, 4), (1, 2, 4), (1, 3, 4), (1, 4, 4), (2, 1, 4), (2, 3, 4),

    (3, 1, 4), (3, 2, 4), (3, 3, 4), (3, 4, 4), (4, 1, 4), (4, 3, 4)

    Solution:

      本题容斥+暴力枚举。

      因为要向左移动1位,所以可以得到一个线性方程$a_1x_1+a_2x_2+…+a_nx_n=1$,满足有解的情况时,由裴蜀定理得$gcd(x_1,x_2…,x_n)=1$,我们只要满足任意两个数$gcd(x_i,x_j)=1$就好了。

      我们先求出总的方案数$m^n$,再从中减去所有的整体gcd不为1的情况,由于整体gcd不为1的情况必须满足gcd为m的约数。

      于是我们枚举m的约数作为整体公约数,对于约数$a$,共有$frac{m}{a}$个含约数a的数,那么减去$(frac{m}{a})^n$,然后由于会重复减,所以还得容斥,由于枚举的是m的因子,所以容斥时可以直接用莫比乌斯函数咯,所以只要求$sum_limits{d|m}^{m}{mu(d)*(frac{m}{d})^n}$就行啦。

    代码:

    /*Code by 520 -- 9.9*/
    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    #define RE register
    #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    ll n,m,ans;
    int prime[40005],cnt;
    
    int u(int x){
        if(x==1)return 1;
        int num=0;
        for(RE int i=2;i*i<=x;i++){
            if(x%i==0) {
                num++;
                RE int p=0;
                while(x%i==0) {
                    x/=i,p++;
                    if(p>1)return 0;
                }
            }
        }
        if(x>1) num++;
        return num&1?-1:1;
    }
    
    ll fast(ll s,ll k){
        ll ans=1;
        while(k){
            if(k&1)ans=ans*s;
            k>>=1;
            s*=s;
        }
        return ans;
    }
    
    void dfs(int now,ll s){
        if(now>cnt) {ans+=u(s)*fast(m/s,n);return;}
        dfs(now+1,s),dfs(now+1,s*prime[now]);
    }
    
    int main(){
        cin>>n>>m;
        int x=m;
        for(RE int i=2;i*i<=m;i++)
            if(x%i==0){
                prime[++cnt]=i;
                while(x%i==0) x/=i;
            }
        if(x>1) prime[++cnt]=x;
        dfs(1,1);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    spring cloud 入门系列三:使用Eureka 搭建高可用服务注册中心
    spring cloud 入门系列二:使用Eureka 进行服务治理
    spring cloud 入门系列一:初识spring cloud
    Java网络编程基础(Netty预备知识)
    spring boot 系列之五:spring boot 通过devtools进行热部署
    spring boot 系列之四:spring boot 整合JPA
    spring boot 系列之三:spring boot 整合JdbcTemplate
    spring boot 系列之二:spring boot 如何修改默认端口号和contextpath
    关于window.location.href 传中文参数 乱码问题
    Ajax前台返回JSON数据后再Controller中直接转换成类型使用,后台接收json转成实体的方法
  • 原文地址:https://www.cnblogs.com/five20/p/9630960.html
Copyright © 2011-2022 走看看