Numbers
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5522
解题思路:
先排序然后从大到小枚举i,把右边的数用一个数组标记其出现过,再枚举左边的数判断其加上Ai是否出现过.
中文题目:
给n个数A1,A2....An,从中选3个位置不同的数A,B和C,问是否有一种情况满足A-B=C.
输入有多组数据,不超过1000组. 每组数据第一行包含一个整数n,随后一行n个整数A1,A2....An.(3≤n≤100,0≤Ai≤1000)
对于每组数据如果符合条件输出"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≤N≤10000,1≤S,T≤N)
对于每组数据输出一行,表示使用超能力的最少次数,如果不可能离开,输出-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≤N≤1018)
对于每组数据输出一行,表示不同节点数的子树有多少种.
算法思想:
一颗完全二叉树,左右子树都会为完全二叉树,其中必然有一个最后一层是满的。对于最后一层是满的完全二叉树,每一层的节点的子树形态都是相同的,只统计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个数A1,A2....An,表示N=∏i=1niAi。求N所有约数之积。
输入有多组数据. 每组数据第一行包含一个整数n.(1≤n≤105) 第二行n个整数A1,A2....An,保证不全为0.(0≤Ai≤105). 数据保证 ∑n≤500000.
对于每组数据输出一行为答案对109+7取模的值.
算法思想:
把N化成N=∏i=1kpiai,其中p为互不相等的质数,则含px个数为j的约数有ax+1∏i=1k(ai+1)个,而j的取值范围是0到ax,从而得到px在所有约数中出现了2(1+ax)ax∗ax+1∏i=1k(ai+1)次。根据费马小定理ap−1≡1(modp),统计ax时可以对p-1取模,由于后面还要除2,所以先对2(p-1)取模。求ax+1∏i=1k(ai+1)部分时不能取逆元,可以分别对前缀和后缀计算积。计算出N包含的所有质因子出现次数后用快速幂统计一遍,复杂度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;
}