您的位置:首页 > 其它

杭电数论入门习题

2016-07-05 21:28 423 查看

HDU 1973 Prime Path

这道题是一道从起点到终点的问题,很明显可以用广搜搜索最小步数即可,同理也可以用最短路,但是需要建边,时间复杂度低。

#include <cstdio>
#include <queue>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 10005;
bool prime[maxn],vis[maxn];
char a[5],b[5];

void init()            //生成素数表,不然每次都判断很耗时
{
memset(prime, false, sizeof(prime));
for(int i = 2; i < maxn; i++) if(!prime[i])
for(int j = i*i; j < maxn; j += i)
prime[j] = true;
}

struct Node        //这里我将整数当做字符串处理的,但是当整数处理可能操作会麻烦,但是时间更快
{
char s[5];
int step;
};

int bfs()
{
queue <Node> que;
Node pre,cur;
memset(vis, false, sizeof(vis));
memcpy(pre.s, a, sizeof(a));  //字符串复制函数
pre.step = 0;
que.push(pre);
vis[atoi(a)] = true;         //atoi函数将字符串转化为整形
while(!que.empty())
{
pre = que.front();
que.pop();
if(!strcmp(pre.s,b))
return pre.step;
for(int i = 0; i < 4; i++)
{
for(int j = 0; j < 10; j++)
{
if(!i && !j) continue; //最高位不改为0
memcpy(cur.s, pre.s,sizeof(pre.s));
cur.s[i] = j + '0';
int temp = atoi(cur.s);
if(!vis[temp] && !prime[temp])
{
vis[temp] = true;
cur.step = pre.step + 1;
que.push(cur);
}
}
}
}
return -1;
}

int main()
{
int T;
scanf("%d", &T);
init();
while(T--)
{
scanf("%s%s", a, b);
int ans = bfs();
if(ans == -1) printf("Impossible\n");
else printf("%d\n", ans);
}
return 0;
}


HDU 1930 And Now, a Remainder from Our Sponsor

这道题看着麻烦,其实写起来还是挺简单的,有一些小细节还是需要处理的,比如一个6位数如何分割问题,还要最后剩余可能一个空格,后者2个空格的处理问题,详细看代码。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
char str[55][10];
int a[10],b[10],c[55];

void exgcd(int a, int b, int &x, int &y)
{
if(b == 0)
{
x = 1;
y = 0;
return;
}
exgcd(b, a % b, y, x);
y -= (a/b)*x;
}

int CRT(int a[],int m[],int n)
{
int M = 1;
int ans = 0;
for(int i=0; i<n; i++)
M *= m[i];
for(int i=0; i<n; i++)
{
int x, y;
int Mi = M / m[i];
exgcd(Mi, m[i], x, y);
ans = (ans + Mi * x * a[i]) % M;
}
if(ans < 0) ans += M;
return ans;
}

int main()
{
int T,n;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = 0; i < 4; i++)
scanf("%d", &a[i]);
for(int i = 0; i < n; i++)
scanf("%d", &c[i]);
for(int i = 0; i < n; i++)
{
for(int j = 3; j >= 0; j--)  //倒着求
{
b[j] = c[i]%100;
c[i] /= 100;
}
int ans = CRT(b, a, 4);
for(int j = 2 ; j >= 0; j--)
{
b[j] = ans%100;
ans /= 100;
}
if(i != n-1)
{
for(int j = 0 ; j < 3; j++)
if(b[j] == 27) printf(" ");
else printf("%c", b[j]+'A'-1);
}
else    //最后的空格处理问题
{
if(b[2] == 27)
{
b[2] = 0;
if(b[1] == 27)
b[1] = 0;
}
for(int j = 0 ; j < 3; j++)
if(b[j] == 27) printf(" ");
else if(b[j]) printf("%c", b[j]+'A'-1);
}
}
printf("\n");
}
return 0;
}


HDU 1920 Jackpot

水题,求最小公倍数

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
int a[5];

int main()
{
int n,m;
while(scanf("%d", &n) != EOF)
{
while(n--)
{
scanf("%d", &m);
for(int i = 1; i <= m; i++)
scanf("%d", &a[i]);
LL ans = 1,j;
for(int i = 1; i <= m; i++)
{
for(j = 1; (j*ans)%a[i] != 0; j++);
ans *= j;
if(ans > 1000000000) break;
}
if(ans > 1000000000) printf("More than a billion.\n");
else printf("%I64d\n", ans);
}

}
return 0;
}


HDU 1788 Chinese remainder theorem again

这道题同样没什么难点,但是需要转化一下。N%M=(M-a)转化为(N+a)%M=0,因此同样成了求最小公倍数的问题。

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

int b[15];

int main()
{
int I,a;
while(scanf("%d%d", &I, &a) != EOF)
{
if(!I && !a) break;
for(int i = 1; i <= I; i++)
scanf("%d", &b[i]);
LL ans = 1,j;
for(int i = 1; i <= I; i++)
{
for(j = 1; (ans*j)%b[i]; j++);
ans *= j;
}
printf("%I64d\n", ans - a);
}
return 0;
}


HDU 1787 GCD Again

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

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

int main()
{
int N;
while(scanf("%d", &N) != EOF && N)
{
int ans = euler(N);
printf("%d\n", N-1-ans);
}
return 0;
}


HDU 1452 Happy 2004

/*
设S(x)表示x的因子和。则题目求为:S(2004^X)mod 29
因子和S是积性函数,即满足性质1。

性质1 :如果 gcd(a,b)=1  则 S(a*b)= S(a)*S(b)
2004^X=4^X * 3^X *167^X
S(2004^X)=S(2^(2X)) * S(3^X) * S(167^X)

性质2 :如果 p 是素数 则 S(p^X)=1+p+p^2+...+p^X = (p^(X+1)-1)/(p-1)
因此:S(2004^X)=(2^(2X+1)-1) * (3^(X+1)-1)/2 * (167^(X+1)-1)/166
167%29 == 22
S(2004^X)=(2^(2X+1)-1) * (3^(X+1)-1)/2 * (22^(X+1)-1)/21

性质3 :(a*b)/c %M= a%M * b%M * inv(c)
其中inv(c)即满足 (c*inv(c))%M=1的最小整数,这里M=29
则inv(1)=1,inv(2)=15,inv(22)=15

有上得:
S(2004^X)=(2^(2X+1)-1) * (3^(X+1)-1)/2 * (22^(X+1)-1)/21
=(2^(2X+1)-1) * (3^(X+1)-1)*15 * (22^(X+1)-1)*18
*/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 29;

int sum(int a,int b)   //快速幂
{
int ans = 1;
while(b)
{
if(b&1) ans = (ans*a)%mod;
a = (a*a)%mod;
b = b>>1;
}
return ans;
}

int main()
{
int X;
while(scanf("%d", &X) != EOF && X)
{
int a,b,c;
a = (sum(2,2*X+1)-1);
b = (sum(3,X+1)-1);
c = (sum(167,X+1)-1);
printf("%d\n", (a*b*15*c*18)%29);
}
return 0;
}


HDU 1370 Biorhythms

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int MOD = 21252;

void exgcd(int a,int b,int &x,int &y)
{
if(b == 0)
{
x = 1;
y = 0;
}
else
{
exgcd(b, a%b, y, x);
y -= (a/b)*x;
}
}

int CRT(int a[],int m[],int n)
{
int M = 1;
int ans = 0;
for(int i = 0; i < n; i++)
M *= m[i];
for(int i = 0; i < n; i++)
{
int Mi = M/m[i];
int x,y;
exgcd(Mi, m[i], x, y);
ans = (ans + Mi*x*a[i])%M;
}
if(ans < 0) ans += M;
return ans;
}

int main()
{
getchar();
int a[5],m[5] = {23, 28, 33};
int d,kase = 1;
while(scanf("%d%d%d%d", &a[0], &a[1], &a[2], &d) != EOF)
{
if(a[0] == -1 && a[1] == -1 && a[2] == -1 && d == -1)
break;
int ans = CRT(a, m, 3);
if(ans <= d) ans += MOD;
printf("Case %d: the next triple peak occurs in %d days.\n", kase++, ans-d);
}
return 0;
}


HDU 1299 Diophantus of Alexandria

这道题非常需要转化,假设y = (n+k),则x = n*(n+k)/k;若n = p1 ^ e1 * p2 ^ e2 ……….*pn ^ en,则n的质因子为sum ( n)= ( 1 + e1 ) ( 1 +e2 ) * ………* ( 1 +en ),则n*n则质因子为( 1 + 2*e1 ) * ( 1 +2*e2 ) * ………* ( 1 +2*en ),这样就可以求解了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 4000;
bool isprime[maxn];
int prime[maxn];

int init()
{
int cnt = 0;
memset(isprime, 0, sizeof(isprime));
for(int i = 2; i < maxn; i++)if(!isprime[i])
for(int j = i*i; j < maxn; j += i)
isprime[j] = true;
for(int i = 2; i < maxn; i++)
if(!isprime[i]) prime[cnt++] = i;
return cnt;
}

int main()
{
int T,cnt,n;
scanf("%d", &T);
cnt = init();
for(int kase = 1; kase <= T; kase++)
{
scanf("%d", &n);
LL sum = 1;
int temp = n;
for(int i = 0; i < cnt && prime[i] < temp; i++)
{
int ans = 0;
while(n % prime[i] == 0)
{
n /= prime[i];
ans++;
}
sum *= (2*ans+1);
}
if(n > 1) sum *= 3;  //比如当n等于2的时候
printf("Scenario #%d:\n%I64d\n\n", kase, (sum+1)/2);
}
return 0;
}


HDU 1719 Friend

假设Fn=a*b+a+b,转化可得Fn+1 = (a+1)*(b+1),又因为a,b的初始值为1,2,因此对于每一个成立的数n,n+1能整除2或者3.注意要考虑n为0的情况。

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

int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
if(!n)
{
printf("NO!\n");
continue;
}
n++;
while(n%2 == 0) n /= 2;
while(n%3 == 0) n /= 3;
if(n == 1) printf("YES!\n");
else printf("NO!\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: