[BZOJ1220][POJ1091][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。

输出

输出文件有且仅有一行,即可以完成任务的卡片数。 1≤M≤10^8,1≤N≤M,且M^N≤10^16。(注意:这个数据范围是错的,此题需要高精度。)

输入示例

2 4

输出示例

12

数据规模及约定

此题需要高精度!(POJ 上的不用,HNOI2002 原题也不用)

题解

其实就是找 N+1 个数互质的方案数,注意到最后一个数是固定的 M,所以可以给它分解质因数,然后容斥一下。MN - 前 N 个数中含有 1 个 M 的质因子的方案数 + 前 N 个数中含有 2 个 M 的质因子的方案数 - ... = ans

最后贴一个高精度模板,搞定。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
    if(Head == Tail) {
        int l = fread(buffer, 1, BufferSize, stdin);
        Tail = (Head = buffer) + l;
    }
    return *Head++;
}
int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define MAXN 1000+10
struct bign
{
    int len, s[MAXN];
    bign ()
    {
        memset(s, 0, sizeof(s));
        len = 1;
    }
    bign (int num) { *this = num; }
    bign (const char *num) { *this = num; }
    bign operator = (const int num)
    {
        char s[MAXN];
        sprintf(s, "%d", num);
        *this = s;
        return *this;
    }
    bign operator = (const char *num)
    {
        for(int i = 0; num[i] == ‘0‘; num++) ;  //去前导0
        len = strlen(num);
        for(int i = 0; i < len; i++) s[i] = num[len-i-1] - ‘0‘;
        return *this;
    }
    bign operator + (const bign &b) const //+
    {
        bign c;
        c.len = 0;
        for(int i = 0, g = 0; g || i < max(len, b.len); i++)
        {
            int x = g;
            if(i < len) x += s[i];
            if(i < b.len) x += b.s[i];
            c.s[c.len++] = x % 10;
            g = x / 10;
        }
        return c;
    }
    bign operator += (const bign &b)
    {
        *this = *this + b;
        return *this;
    }
    void clean()
    {
        while(len > 1 && !s[len-1]) len--;
    }
    bign operator * (const bign &b) //*
    {
        bign c;
        c.len = len + b.len;
        for(int i = 0; i < len; i++)
        {
            for(int j = 0; j < b.len; j++)
            {
                c.s[i+j] += s[i] * b.s[j];
            }
        }
        for(int i = 0; i < c.len; i++)
        {
            c.s[i+1] += c.s[i]/10;
            c.s[i] %= 10;
        }
        c.clean();
        return c;
    }
    bign operator *= (const bign &b)
    {
        *this = *this * b;
        return *this;
    }
    bign operator - (const bign &b)
    {
        bign c;
        c.len = 0;
        for(int i = 0, g = 0; i < len; i++)
        {
            int x = s[i] - g;
            if(i < b.len) x -= b.s[i];
            if(x >= 0) g = 0;
            else
            {
                g = 1;
                x += 10;
            }
            c.s[c.len++] = x;
        }
        c.clean();
        return c;
    }
    bign operator -= (const bign &b)
    {
        *this = *this - b;
        return *this;
    }
    bign operator / (const bign &b)
    {
        bign c, f = 0;
        for(int i = len-1; i >= 0; i--)
        {
            f = f*10;
            f.s[0] = s[i];
            while(f >= b)
            {
                f -= b;
                c.s[i]++;
            }
        }
        c.len = len;
        c.clean();
        return c;
    }
    bign operator /= (const bign &b)
    {
        *this  = *this / b;
        return *this;
    }
    bign operator % (const bign &b)
    {
        bign r = *this / b;
        r = *this - r*b;
        return r;
    }
    bign operator %= (const bign &b)
    {
        *this = *this % b;
        return *this;
    }
    bool operator < (const bign &b)
    {
        if(len != b.len) return len < b.len;
        for(int i = len-1; i >= 0; i--)
        {
            if(s[i] != b.s[i]) return s[i] < b.s[i];
        }
        return false;
    }
    bool operator > (const bign &b)
    {
        if(len != b.len) return len > b.len;
        for(int i = len-1; i >= 0; i--)
        {
            if(s[i] != b.s[i]) return s[i] > b.s[i];
        }
        return false;
    }
    bool operator == (const bign &b)
    {
        return !(*this > b) && !(*this < b);
    }
    bool operator != (const bign &b)
    {
        return !(*this == b);
    }
    bool operator <= (const bign &b)
    {
        return *this < b || *this == b;
    }
    bool operator >= (const bign &b)
    {
        return *this > b || *this == b;
    }
    string str() const
    {
        string res = "";
        for(int i = 0; i < len; i++) res = char(s[i]+‘0‘) + res;
        return res;
    }
};

istream& operator >> (istream &in, bign &x)
{
    string s;
    in >> s;
    x = s.c_str();
    return in;
}  

ostream& operator << (ostream &out, const bign &x)
{
    out << x.str();
    return out;
}

#define maxn 50
#define LL bign
int n, m;

int prime[maxn], cnt;
void getprime(int x) {
	int t = sqrt(x + .5);
	for(int i = 2; i <= t; i++) if(x % i == 0) {
		prime[++cnt] = i;
		while(x % i == 0) x /= i;
	}
	if(x > 1) prime[++cnt] = x;
	return ;
}

LL Pow(LL a, int b) {
	LL ans = 1, t = a;
	while(b) {
		if(b & 1) ans *= t;
		t *= t; b >>= 1;
	}
	return ans;
}

int main() {
	n = read(); m = read();

	getprime(m);
	LL ans = Pow(m, n);
	int all = (1 << cnt) - 1;
	for(int i = 1; i <= all; i++) {
		int tmp = 1; int c = 0;
		for(int j = 1; j <= cnt; j++) if(i >> j - 1 & 1) tmp *= prime[j], c++;
		LL tt = Pow(m / tmp, n);
		if(c & 1) ans -= tt; else ans += tt;
	}

	cout << ans << endl;

	return 0;
}
时间: 2024-10-18 21:08:19

[BZOJ1220][POJ1091][HNOI2002]跳蚤的相关文章

[HNOI2002]跳蚤

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

【poj1091】 跳蚤

http://poj.org/problem?id=1091 (题目链接) 题意 给出一张卡片,上面有n+1个数,其中最大的数为m,每次可以向前或者向后走卡片上面的步数.问有多少种方案选出n个数,使得存在一种走的方案经过若干步后可以达到与起点距离为1的位置上. Solution 今天考试题,又是一道大原题... 我们假设卡片上的数分别为:{a1,a2,a3,a4······an,m},那么如果要满足题目要求,就是说存在一个数列x:{x1,x2,x3,x4······xn,xn+1}使得a1x1+

poj1091:跳蚤【容斥原理】

题目大意:中文题就不翻译了 思路:假设跳蚤选择X1个第一张卡片,X2个第二张卡片...Xn个第n张卡片,Xn+1张写着m的卡片,那么就可以列出方程:a1*X1+a2*X2+…+an*Xn+m*X(n+1)=1 由于可以向左跳和向右跳,因此题目即问上述不定方程是否有解?答案以及它的证明可以在任何一本数论书中找到,它的充要条件是(a1,a2,a3...an,m)|1 即a1,a2,a3...an,m互质,这样题目就成为:有n+1个正整数,其中最大的数为m,问所有符合条件的序列中有多少是互质的. 组合

poj1091跳蚤(容斥定理)

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

bzoj 4310: 跳蚤

Description 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个,并在选出来的 k 个子串中选择字典序最大的那一个.他称其为"魔力串". 现在他想找一个最优的分法让"魔力串"字典序最小. Input 第一行一个整数 k. 接下来一个长度不超过 105 的字符串 S. Output 输出一行,表示字典序最小的"

BZOJ 1588: [HNOI2002]营业额统计

1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 14396  Solved: 5521[Submit][Status][Discuss] Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其

小JAVA大世界之程序建模跳蚤实验

package com.chigoe;//房子类class House { private int m;// 保存行数 private int n;// 保存列数 private int[][] a; public House() { // 无参构造方法 m = 10; n = 10; for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) { a[i][j] = 0; } } public House(int m,int n){//带参

P2234 [HNOI2002]营业额统计 (权值线段树)

P2234 [HNOI2002]营业额统计 题目描述 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题.经济管理学上定义了一种最小波动值来衡量这种情况: 当最小波动值越大

【bzoj4310】跳蚤 后缀数组+二分

题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个,并在选出来的 k 个子串中选择字典序最大的那一个.他称其为“魔力串”. 现在他想找一个最优的分法让“魔力串”字典序最小. 输入 第一行一个整数 k. 接下来一个长度不超过 105 的字符串 S. 输出 输出一行,表示字典序最小的“魔力串”. 样例输入 13 bcbcbacbbbbbabbacbcb