算法导论集(3)

A. 三个师妹之出题

Description

这一次,那几个师妹给sharp出了一个题目:给定一个正整数N,求1/X+1/Y= 1/N的所有正整数解.sharp哈哈笑了两声,很简单的题目嘛....但是他一听数据范围就傻眼了,N最大可能是999999999!!!聪明的你能帮帮可怜的sharp吗?好让他不那么丢脸.

Input

第一行输入一个正整数M,下面有M行,每一行都是一个正整数N.

Output

输出共M行,每行都是方程解的个数.

Sample Input

2
1
2

Sample Output

1
3
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
long long a[20],b[20];
long long gs;
int main()
{
	long long n,i,j,k,x,z,ans;
	scanf("%lld",&x);
	for(k=1;k<=x;k++)
	{
		scanf("%lld",&n);
		z=n;
		memset(b,0,sizeof(b));
		memset(a,0,sizeof(a));
		if(n<=3)
		{
			gs=1;
			a[0]=n;
			b[0]=1;
		}
		else
		{
			gs=0;
			i=2;
			while(i*i<=n)
			{
				while(n%i==0)
				{
					b[gs]++;
					n/=i;
				}
				if(b[gs]>0)
				{
					a[gs]=i;
					gs++;
				}
				i++;
			}
			if(n>1)
			{
				a[gs]=n;
				b[gs]=1;
				gs++;
			}
		}
		if(z<2)
		{
			cout<<1<<endl;
		}
		else
		{
			ans=1;
			for(i=0;i<gs;i++)
			{
				ans*=2*b[i]+1;
			}
			cout<<ans<<endl;
		}
	}
    return 0;
}

B. 整数分解

Description

根据数论的有关理论可知,任何大于1的正整数都可唯一地表示为形如(P1^N1)*(P2^N2)*…(Pm^Nm)的形式。请你编程序实现。

Input

输入:第一行是测试数据的组数N(N小于10000),接着是N行正整数,每行一个,每个正整数不超过32767。

Output

输出:形式是M=(P1^N1)*(P2^N2)*…(Pm^Nm)。

说明:(a)如果幂的值为1,则不用写括号和1次幂;如:15=3*5。

(b)如果N是素数,也不用写括号和1次幂;如:7=7。

(c)如果因子只有一个,也不用写括号;如:27=3^3。

Sample Input

2
25608
24027

Sample Output

25608=(2^3)*3*11*97
24027=3*8009
#include<bits/stdc++.h>
using namespace std;
struct jg
{
    int p,m;
};
jg a[21];
bool ss(int x);
int main()
{
    int n,i,k,x,t,c;
    cin>>n;
    for(k=1;k<=n;k++)
    {
        for(i=1;i<=20;i++)
        {
            a[i].m=0;
            a[i].p=0;
        }
        t=0;
        scanf("%d",&x);
        cout<<x<<'=';
        if(x==1)
        {
            cout<<1<<'^'<<0<<endl;
            continue;
        }
        c=x;
        for(i=2;i<=x;i++)
        {
            if(x%i==0)
            {
                t++;
            }
            while(x%i==0&&x!=0)
            {
                a[t].p=i;
                a[t].m++;
                x/=i;
            }
        }
        if(ss(c))
        {
            cout<<c<<endl;
        }
        else
        {
            if(a[2].m==0&&a[2].p==0)
            {
                cout<<a[1].p<<'^'<<a[1].m<<endl;
            }
            else
            {
                for(i=1;i<t;i++)
                {
                    if(a[i].m==1)
                    {
                        cout<<a[i].p<<'*';
                    }
                    else
                    {
                        cout<<'('<<a[i].p<<'^'<<a[i].m<<")*";
                    }
                }
                if(a[t].m==1)
                {
                    cout<<a[t].p<<endl;
                }
                else
                {
                    cout<<'('<<a[t].p<<'^'<<a[t].m<<')'<<endl;
                }
            }
        }
    }
    return 0;
}
bool ss(int x)
{
    int i;
    if(x==2)
    {
        return true;
    }
    if(x<3)
    {
        return false;
    }
    for(i=2;i<=sqrt(x);i++)
    {
        if(x%i==0)
        {
            return false;
        }
    }
    return true;
}

C. 找新朋友

Description

新年快到了,“猪头帮协会”准备搞一个聚会,已经知道现有会员N人,把会员从1到N编号,其中会长的号码是N号,凡是和会长是老朋友的,那么该会员的号码肯定和N有大于1的公约数,否则都是新朋友,现在会长想知道究竟有几个新朋友?请你编程序帮会长计算出来。

Input

输入:第一行是测试数据的组数CN(Case number,1<cn<10000),接着有CN行正整数N(1<n<32768),表示会员人数。

Output

输出:对于每一个N,输出一行新朋友的人数,这样共有CN行输出。

Sample Input

2
25608
24027

Sample Output

7680
16016
#include<bits/stdc++.h>
using namespace std;
long long a[20],b[20];
long long gs;
int Aoligei(int x,int y);
int main()
{
	long long n,i,j,k,x,z,ans;
	scanf("%lld",&x);
	for(k=1;k<=x;k++)
	{
		scanf("%lld",&n);
		z=n;
		ans=1;
		for(i=2;i<=n;i++)
        {
            gs=0;
            while(n%i==0)
            {
                n/=i;
                gs++;
            }
            if(gs!=0)
            {
                ans*=Aoligei(i,gs-1)*(i-1);
            }
        }
        cout<<ans<<endl;
	}
    return 0;
}
int Aoligei(int x,int y)
{
    int i,z;
    z=1;
    for(i=1;i<=y;i++)
    {
        z*=x;
    }
    return z;
}

D. 小学生都会算的A+B问题

Description

大家都知道OJ上的最简单的题目就是A+B了,今天我们还是做这个A+B,不过这个数非常大,两个加数的位数不超过100000位,请你写个程序试试吧。

Input

输入有两行,每行一个正整数。

Output

输出只有一行,即两个正整数的和。

Sample Input

12345
67890123

Sample Output

67902468
//大家都知道OJ上的最简单的题目就是A+B了,今天我们还是做这个A+B,不过这个数非常大,两个加数的位数不超过100000位,请你写个程序试试吧。

#include <bits/stdc++.h>
using namespace std;

string sGetAB(string sA,string sB);//将两个string按数字加法的方式相加
void vOut(string sAB);//输出最后相加得到的值(string)
string sValid(string sC);//判断加法的值是否合法,前面可能会有多补的 '0'

int main(){
    string sA,sB,sAB;
    while (cin>>sA>>sB){
        sAB= sGetAB(sA,sB);
        sAB= sValid(sAB);
        vOut(sAB);
    }
    return 0;
}

string sGetAB(string sA,string sB){
    int nSum,nCarry;//nSum用来记录一位加法的结果,nCarry用来记录进位
    string sRet; //用来相加的存放结果
    int nLenA,nLenB,nLenAB;//用来记录三个string字符的长度
    string sTemp; //中间变量

    nLenA=sA.size();
    nLenB=sB.size();
    if(nLenA>nLenB){//A的长度大于B时
        sTemp.resize(nLenA-nLenB,'0');  // 提前将sA和sB位数的差值赋为0
        sB=sTemp+sB; //因为sB是短的那个,先给它的前面补上0
        nLenAB=nLenA;
    }else{//同理,当情况为A的长度小于B时,相等的时候,补上的0的个数是0个
        sTemp.resize(nLenB-nLenA,'0');
        sA=sTemp+sA;
        nLenAB=nLenB;
    }
    sRet.resize(nLenAB,'0');//先给相加的结果值初始化为与sA和sB等长的 0

    nCarry=0;//进位初始化0
    for (int i = nLenAB-1; i >= 0 ; i--) {
        nSum=(sA[i]-'0')+(sB[i]-'0')+nCarry; //从最低位开始加,nCarry是进位
        sRet[i]=(char)(nSum%10+'0');//位上只能是 '0'到'9' 所以要 %10 ,并且加上'0'的ascii码值,最后再用char转换为对应的字符
        nCarry=nSum/10;//记录下进位,在做下一次的位加法时,一并加上
    }
    if (nCarry==1){//代表最高位加完后,产生了进位,手动再在前面给他加上1位的'1'
        sRet='1'+sRet;
    }
    return sRet;
}

string sValid(string sC){
    string sRet;
    int i=0;
    while(i<sC.size()&&sC[i]=='0'){ //从左到右遍历,即从高位到低位遍历,记录前面多了几个 '0',后面要去除掉
        i++;
    }
    if (i==sC.size()){
        sRet='0'; //这里是当结果全是0的时候,不能把0全部摒弃,手动给结果赋一个'0'
    }else{
        sRet=sC.substr(i,sC.size()-i); //有多余的'0',只取后面的非'0'部分 ,从i这个位置开始取,取的长度为 sC.size()-i
    }
    return sRet;
}

void vOut(string sAB){ //打印最后的结果
    cout<<sAB<<endl;
}

E. 幂运算精确值计算问题

Description

输入两个不超过10000的正整数a、n正整数n,输出a^n的精确结果。

Input

本问题有多组测试数据,对于每一组测试数据,只有一行,每行有用空格隔开的两个正整数。

Output

对于每一组测试数据,输出只有一行,即计算的结果。

Sample Input

2 3
91 37

Sample Output

8
3051627471597949451463369059654147285577479747909625754790616546501477931
//幂运算精确值计算问题
//输入两个不超过10000的正整数a、n正整数n,输出a^n的精确结果。
//最大值是 10000 的 10000 次方,也就是 10**(4*10000)=10 **(40000),所以最大是40001位

#include <bits/stdc++.h>
using namespace std;
#define MAX 40002 //由上面可得MAX的值,正好是40001位,因为下面j可能会比最大的实际情况40001多1位,尽管不会访问nBits[40001](从0开始,也就是第40002位),但设置为40002也是合理的
int nBits[MAX];//用数组来存储最后的结果值
int nBitsNum;//最后结果值的位数
void vInit();
void vPower(int nA,int nN);
void vOut(int nPos);

int main(){
    int nA,nN;
    while(cin>>nA>>nN){
        if (nA==1){// 1的任何次幂都是1,所以直接输出
            cout<<"1"<<endl;
        }else{ //其余的正常情况如下
            vInit();
            vPower(nA,nN);
            vOut(nBitsNum);
        }
    }
    return 0;
}

void vInit(){
    nBitsNum=1;//先初始化,结果至少有1位
}

void vPower(int nA,int nN){
    int nCarry,nTemp;
    int i,j;

    nBits[0]=1;//先将最低位赋为1,不然得不到第一次乘的值,第一步是要将nA与最低位相乘的
    for ( i = 1; i <= nN; i++) { //因为要乘nN次,这里从1开始
        nCarry=0;
        j=0;//j每次都从0开始,是因为做乘法每次从最低位开始的
        while (true){
            if (j<nBitsNum){//判断此时的j是否超过了nBitsNum,如果等于或者大于,则要去else里判断是否需要进位 ,为什么是j<nBitsNum?,继续看下面的分析
                nTemp=nBits[j]*nA+nCarry;//正常的乘法与加上前一次的进位
                nBits[j]=nTemp%10;//每位只能是'0'-'9',所以要取余
                nCarry=nTemp/10;//记录下进位,在下次运算时加上
            }else{
                if (nCarry==0){//如果没有进位,正常结束本次的乘法
                    break;
                }
                nBits[j]=nCarry%10;//否则继续进位
                nCarry=nCarry/10;
            }
            j++;//处理完本位,继续往前加位数
        }
        nBitsNum=j;//每次乘法结束后更新nBitsNum的值,nBitsNum每次比实际上用到的j会大1,因为在break出来本次循环的上次循环中执行过 j++
    }
}

void vOut(int nPos){
    for (int i = nPos-1; i >= 0; i--) { //因为nPos==nBitsNum,而每次比实际上用到的j会大1,所以是nPos-1
        cout<<nBits[i];
    }
    cout<<endl;
}

G. 多项式的和

Description

This time, you are supposed to find A+B where A and B are two polynomials.

这一次你的任务是求解A+B,这里的A和B是两个多项式

Input

Each input file contains multiple test case. Each case occupies 2 lines, and each line contains the information of a polynomial: K N1 aN1 N2 aN2 ... NK aNK, where K is the number of nonzero terms in the polynomial, Ni and aNi (i=1, 2, ..., K) are the exponents and coefficients, respectively. It is given that 1 <= K <= 10,0 <= NK < ... < N2 < N1 <=1000.

每个输入文件包含多组测试数据,每组测试数据有2行,每行数据是一个多项式的信息:K N1 aN1 N2 aN2 … NK aNK,其中K是非零整数,表示多项式的项数,Ni和aNi(i=1,2,…,K))表示每一项的幂和系数,K和NK符合1 <= K <= 10,0 <= NK < ... < N2 < N1 <=1000。

Output

For each test case you should output the sum of A and B in one line, with the same format as the input. Notice that there must be NO extra space at the end of each line. Please be accurate to 1 decimal place.

对于每一组测试数据,输出只有一行,即两个多项式的和,输出的格式和输入一样,输出行的末尾没有多余的空格,输出保留一位小数。

Sample Input

2 1 2.4 0 3.2
2 2 1.5 1 0.5

Sample Output

3 2 1.5 1 2.9 0 3.2
#include <math.h>
#include <stdio.h>
using namespace std;
#define MAX 1001
#define EPS 0.05

void Input();
void Clear();
void Add();
void Output();

double a[MAX],b[MAX],c[MAX];//数组a和b是分别用来记录这两组输入的多项式,c是用来记录相加的结果的
int n,k;

int main(){
    while(1== scanf("%d",&k)){
        Clear();
        Input();
        Add();
        Output();
    }
    return 0;
}

void Clear(){
    int i;
    n=0;
    for (i = 0; i < MAX; i++) {
        a[i]=0.0;
        b[i]=0.0;
        c[i]=0.0;
    }
}

void Input(){//输入这两行多项式
    int i,e;
    double temp;
    for (i = 0; i <k; i++) {
        scanf("%d",&e);
        scanf("%lf",&a[e]);
    }
    scanf("%d",&k);
    for (i = 0; i <k; i++) {
        scanf("%d",&e);
        scanf("%lf",&b[e]);
    }
}

void Add(){
    int i;
    for (i=0;i<MAX;i++){
        c[i]=a[i]+b[i];
    }
}

void Output(){
    int i;
    for (i=MAX-1;i>=0;i--){
        if(fabs(c[i])>=EPS){//这道题的重点就是不能直接判断 double类型的值 == 0 ,要设定一个精度EPS,小于这个精度EPS的值都可以认为就是0
            n++;
        }
    }

    if(0==n){
        printf("0\n");
    }else{
        printf("%d",n);
        for (i=MAX-1;i>=0;i--){
            if(fabs(c[i]>=EPS)){
                printf(" %d %.1lf",i,c[i]);
            }
        }
        printf("\n");
    }
}

I. 不一样的S型方阵

Description

同学们都知道大学英语四、六级考试的座位是按照以列为主的S型安排的,今天我们要求输出另外一种S型数字方阵,例如6阶和7阶的图形如Sample所示。你现在的任务是编个程序对于输入的整数N,输出相应的方阵。

Input

本问题有多组测试数据,每组一个整数N。(0<N<=30)

Output

对于每组测试数据,输出一个方阵,每个数字场宽为4。每组最后一行由4N个“=”作为结束行。

Sample Input

6
7
#include <stdio.h>
#include <memory.h>
using namespace std;
#define MAX 31
int n;
int a[MAX][MAX];
 
void Init();
void Order();
void vOut();
 
int main()
{
    while(1==scanf("%d",&n))
    {
        Init();
        Order();
        vOut();
    }
    return 0;
}
void Init()
{
    memset(a,0,sizeof(a));
}
void Order()
{
    int i,j,dig;
    dig=1;
    i=1;
    j=n;
    a[i][j]=dig;
    a[i][--j]=++dig;
    a[++i][++j]=++dig;
    int flag=0;
    int sum=n*(n+1)/2;
    while(dig<sum)
    {
        if(i==1)
        {
            if(a[i+1][j+1]!=0)
            {
                a[i][--j]=++dig;
                flag=1; //从上往下
            }
            else
            {
                a[++i][++j]=++dig;
                 flag=1; //从上往下
            }
        }
        else if(j==n)
        {
            if(a[i-1][j-1]!=0)
            {
                a[++i][j]=++dig;
                 flag=2; //从下往上
            }
            else
            {
                a[--i][--j]=++dig;
                flag=2; //从下往上
            }
 
    }
        if(flag==1)
        {
            a[++i][++j]=++dig;
        }
        else if(flag==2)
        {
             a[--i][--j]=++dig;
        }
    }
    sum=n*n;
    while(dig<=sum)
    {
        if(j==1)
        {
            if(a[i+1][j+1]!=0)
            {
                a[++i][j]=++dig;
                flag=1; //从上往下
            }
            else
            {
                a[++i][++j]=++dig;
                 flag=1; //从上往下
            }
        }
        else if(i==n)
        {
            if(a[i-1][j-1]!=0)
            {
                a[i][--j]=++dig;
                 flag=2; //从下往上
            }
            else
            {
                a[--i][--j]=++dig;
                flag=2; //从下往上
            }
        }
        if(flag==1)
        {
            a[++i][++j]=++dig;
        }
        else if(flag==2)
        {
             a[--i][--j]=++dig;
        }
    }
 
}
void vOut()
{
    int i,j;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            printf("%4d",a[i][j]);
        }
            printf("\n");
    }
    for(i=1;i<=n;i++)
    {
        printf("====");
    }
    printf("\n");
}
 
 
 
 

J. 有趣的箭头

Description

今天你的任务是编程序画箭头图案,箭头一共有四个方向,分别用大写字母L表示朝左,R表示朝右,U表示朝上以及D表示朝下,对于给定的正整数n(n<=100),箭头图案的大小是长和宽各是4n-1,图案中空余地方用空格填充,用来表示箭头部分用给定的字符填充。

如下所示分别是n为2、3、4、5时的星号箭头:

如下所示分别是其他字符和不同方向的箭头图案:

Input

本问题有多组测试数据,每组测试数据只有一行,分别是用空格隔开的一个正整数n和两个字符,第一个字符表示朝向,一定是L、R、U、D之一,后一个字符是填充的字符。

Output

对于每一组测试数据,输出符合要求的箭头图案。

Sample Input

5 R $

Sample Output

         $         
         $$        
         $$$       
         $$$$      
         $$$$$     
$$$$$$$$$$$$$$$    
$$$$$$$$$$$$$$$$   
$$$$$$$$$$$$$$$$$  
$$$$$$$$$$$$$$$$$$ 
$$$$$$$$$$$$$$$$$$$
$$$$$$$$$$$$$$$$$$ 
$$$$$$$$$$$$$$$$$  
$$$$$$$$$$$$$$$$   
$$$$$$$$$$$$$$$    
         $$$$$     
         $$$$      
         $$$       
         $$        
         $         
#include <bits/stdc++.h>

using namespace std;

int n,m;
char s[1005][1005];

int main()
{
    char x,y;
    while(~scanf("%d %c %c",&n,&x,&y))
    {
        int m=(2*n-1)+2*n;
        for(int i=1;i<=2*n-1;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(j<=n||j>n+2*n-1)s[i][j]=' ';
                else s[i][j]=y;
            }
        }
        for(int i=2*n;i<=4*n-1;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(j<(i-2*n+1)||j>m-(i-2*n+1)+1)s[i][j]=' ';
                else s[i][j]=y;
            }

        }
        if(x=='R')
        {
            for(int i=1;i<=m;i++)
            {
                for(int j=1;j<=4*n-1;j++)
                    putchar(s[j][i]);
                puts("");
            }

        }
        else if(x=='L')
        {
            for(int i=1;i<=m;i++)
            {
                for(int j=4*n-1;j>=1;j--)
                    putchar(s[j][i]);
                puts("");
            }
        }
        else if(x=='D')
        {
            for(int i=1;i<=4*n-1;i++)
            {
                for(int j=1;j<=m;j++)
                    putchar(s[i][j]);
                puts("");
            }
        }
        else
        {
            for(int i=4*n-1;i>=1;i--)
            {
                for(int j=1;j<=m;j++)
                    putchar(s[i][j]);
                puts("");
            }

        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值