BestCoder Round #61 (div.2)(hdu5522,hdu5523,hdu5524,hdu5525(数论:费马小定理))

Numbers

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5522

解题思路:

先排序然后从大到小枚举i,把右边的数用一个数组标记其出现过,再枚举左边的数判断其加上Ai是否出现过.

中文题目:


问题描述
给n个数{A}_{1},{A}_{2}....{A}_{n}A1,A2....An,从中选3个位置不同的数A,B和C,问是否有一种情况满足A-B=C.
输入描述
输入有多组数据,不超过1000组.
每组数据第一行包含一个整数n,随后一行n个整数{A}_{1},{A}_{2}....{A}_{n}A1,A2....An.(3\leq n\leq 1003n100,0\leq {A}_{i}\leq 10000Ai1000)
输出描述
对于每组数据如果符合条件输出"YES",否则输出"NO".

算法思想:

由于n的范围最大是100,所以n的三次方也不会超,直接暴力即可。

AC代码:

<p>#include <iostream></p>#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int a[105];

int main(){
    int n;
    while(~scanf("%d",&n)){
        for(int i = 0; i < n; i++)
            scanf("%d",&a[i]);
        int flag = 0;
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                for(int k = 0; k < n; k++){
                    if(i == j || i == k || j == k)
                        continue;
                    if(a[i]+a[j] == a[k] || a[i]+a[k] == a[j] || a[j]+a[k] == a[i]){
                        flag = 1;
                        break;
                    }
                }
                if(flag)
                    break;
            }
            if(flag)
                break;
        }
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}


Game

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5523

解题思路:

中文题目:


问题描述
XY在玩一个游戏:有N根柱子排成一排,编号为1到N,每个柱子上面有一块宝石,现在XY站在第S根柱子上,出口在第T跟柱子上,XY需要拿到所有宝石后从出口离开。每次XY可以走到相邻的柱子上,也可以使用超能力跳到第一根柱子或者第N根柱子上,如果离开了柱子之后再也不能到达这里。为了节省能量,XY想用最少次数超能力通关。
输入描述
输入有多组数据,不超过1000组.
每组数据输入一行包含3个整数,N,S和T.(1\leq N\leq10000,1\leq S,T\leq N )(1N10000,1S,TN)
输出描述
对于每组数据输出一行,表示使用超能力的最少次数,如果不可能离开,输出-1.

算法思想:

无解的情况只有起点和终点位置一样且N不为1。终点和起点都在边界上答案为0,如果起点在边界上或者起点终点相邻答案为1,其他答案为2.

AC代码:

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

int main(){
    int n,s,t;
    while(~scanf("%d%d%d",&n,&s,&t)){
        int ans;
        if(n == 1){
            printf("0\n");
            continue;
        }
        if(s == t)
            ans = -1;
        else if(s == 1 && t == n || s == n && t == 1)
            ans = 0;
        else if(s == 1 || s == n || abs(s-t) == 1)
            ans = 1;
        else
            ans = 2;
        printf("%d\n",ans);
    }
    return 0;
}


Subtrees

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5524

解题思路:

中文题目:


问题描述
一棵有N个节点的完全二叉树,问有多少种子树所包含的节点数量不同。
输入描述
输入有多组数据,不超过1000组.
每组数据输入一行包含一个整数N.(1\leq N\leq {10}^{18})(1N1018)
输出描述
对于每组数据输出一行,表示不同节点数的子树有多少种.

算法思想:

一颗完全二叉树,左右子树都会为完全二叉树,其中必然有一个最后一层是满的。对于最后一层是满的完全二叉树,每一层的节点的子树形态都是相同的,只统计logN种,然后递归处理另一颗子树。最后对记录下的所有子树根据节点数判重.

AC代码:

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

typedef long long ll;
int add,deep,maxdeep;
ll n;

void solve(ll q){
    ll lh = q,rh = q;
    deep = 0;
    while(lh*2 <= n){
        lh *= 2;
        deep++;
    }
    while(rh*2+1 <= n)
        rh = rh*2+1;
    if(lh <= rh){
        maxdeep = deep>maxdeep?deep:maxdeep;
    }
    else{
        solve(2*q);
        solve(2*q+1);
        add++;
    }
}

int main(){
    while(~scanf("%lld",&n)){
        add = 0;
        maxdeep = 0;
        solve(1);
        printf("%lld\n",maxdeep+add+1);
    }
}


Product(数论:费马小定理)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5525

解题思路:


问题描述
给n个数{A}_{1},{A}_{2}....{A}_{n}A1,A2....An,表示N=\prod_{i=1}^{n}{i}^{{A}_{i}}N=i=1niAi。求N所有约数之积。
输入描述
输入有多组数据.
每组数据第一行包含一个整数n.(1\leq n\leq {10}^{5})(1n105)
第二行n个整数{A}_{1},{A}_{2}....{A}_{n}A1,A2....An,保证不全为0.(0\leq {A}_{i}\leq {10}^{5})(0Ai105).
数据保证 \sum n\leq 500000n500000.
输出描述
对于每组数据输出一行为答案对{10}^{9}+7109+7取模的值.

算法思想:

把N化成N=\prod_{i=1}^{k}{{p}_{i}}^{{a}_{i}}N=i=1kpiai,其中p为互不相等的质数,则含{p}_{x}px个数为j的约数有\frac{\prod_{i=1}^{k}({a}_{i}+1)}{{a}_{x}+1}ax+1i=1k(ai+1)个,而j的取值范围是0到{a}_{x}ax,从而得到{p}_{x}px在所有约数中出现了\frac{(1+{a}_{x}){a}_{x}}{2}*\frac{\prod_{i=1}^{k}({a}_{i}+1)}{{a}_{x}+1}2(1+ax)axax+1i=1k(ai+1)次。根据费马小定理{a}^{p-1}\equiv 1(mod p)ap11(modp),统计{a}_{x}ax时可以对p-1取模,由于后面还要除2,所以先对2(p-1)取模。求\frac{\prod_{i=1}^{k}({a}_{i}+1)}{{a}_{x}+1}ax+1i=1k(ai+1)部分时不能取逆元,可以分别对前缀和后缀计算积。计算出N包含的所有质因子出现次数后用快速幂统计一遍,复杂度O(NlogN)O(NlogN).

AC代码:

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

typedef long long ll;
const ll mod = 1000000000 + 7;
const int maxn = 100005;
int vis[maxn];
int prime[maxn];
int nprime;

void init(){
    nprime = 0;
    memset(vis,0,sizeof(vis));
    memset(prime,0,sizeof(prime));
    for(int i = 2; i <= maxn-5; i++){
        int t = (maxn-5)/i;
        for(int j = 2; j <= t; j++){
            vis[i*j] = 1;
        }
    }
    for(int i = 2; i <= maxn-5; i++){
        if(!vis[i])
            prime[nprime++] = i;
    }
}

ll  num[maxn];
int a[maxn];
map<int,map<int, int> > mp;

void get_factor(int x){
    int tx = x;
    for(int i = 0; i < nprime && prime[i] * prime[i] <= x; ++i){
        if(x % prime[i] == 0) {
            int cnt = 0;
            while(x % prime[i] == 0) {
                x /= prime[i];
                cnt++;
            }
            mp[tx][prime[i]] = cnt;
        }
    }
    if(x > 1)
        mp[tx][x] = 1;
    return ;
}

void init2(){
    mp.clear();
    for(int i = 1; i <= 100000; ++i){
        get_factor(i);
    }
    return ;
}

ll power_mod(ll a, ll b){
    ll ret = 1;
    while(b){
        if(b & 1)
            ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret;
}

ll gcd(ll a, ll b){
    if(b == 0)
        return a;
    else
        return gcd(b,a%b);
}

ll extend_gcd(ll a, ll b, ll &x, ll &y) {
    if(b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extend_gcd(b, a % b, y, x);
    y -= x * (a / b);
    return d;
}

ll inv(ll a, ll n){
    ll x, y;
    ll d = extend_gcd(a, n, x, y);
    if(d != 1){
        return -1;
    }
    return (x % n + n) % n;
}

int main(){
    init();
    init2();
    int n;
    while(~scanf("%d", &n)){
        memset(num,0,sizeof(num));
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        ll t = 1;
        for(int i = 2; i <= n; ++i) {
            for(map<int, int>::iterator it = mp[i].begin(); it != mp[i].end(); it++){
                num[it->first] += it->second * a[i];
            }
        }
        bool first = true;
        for(int i = 2; i <= n; ++i){
            if(num[i] > 0) {
                t = t * (num[i] + 1);
                if(t % 2 == 0 && first){
                    t /= 2;
                    first = false;
                }
                t %= (mod - 1);
            }
        }
        ll ans = 1;
        for(int i = 2; i <= n; ++i){
            if(num[i] > 0) {
                ll tt = t;
                tt *= num[i];
                if(tt % 2 == 0 && first){
                    tt /= 2;
                    tt %= (mod - 1);
                }
                ans = ans * power_mod(i, tt) % mod;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值