EOJ-进制转换&多项式专题

进制转换练习
3085.统计1的个数

输入一个非负 int 类型整数,在一行中输出该整数的二进制表示中值为 1 的位数。
例如: 输入 0,输出 0; 输入 1,输出 1; 输入 100,输出 3; 输入 2100012345,输出 18
输入: 输入一个非负 int 类型整数。
输出: 在一行中,输出整数的二进制表示中值为 1 的位数。

#include <stdio.h> 
#include <stdlib.h>
#include<string.h> 
int main(){ 
	long long n=0,i=1; 
	scanf("%lld",&n); 
	int count=0; 
	while(n){ 
		if(n&1)count++; // 与运算:相同的数则保留,不相同的数则为0.所以跟1做与操作只能是1的时候结果为1
		n>>=1; 
	}
	printf("%d\n",count); 
	return 0;
 }

1627.Binary Code

考虑一个 N 位的二进制串 b1…bN,其对应的二进制矩阵为:
然后将这个矩阵的行按照字典顺序排序,‘0’ 在 ‘1’ 之前。
你的任务是编写一个程序,给定排序后的矩阵的最后一列,求出已排序的矩阵的第一行。
例如:考虑二进制串(00110),排序后的矩阵为:
0 0 0 1 1
0 0 1 1 0
0 1 1 0 0
1 0 0 0 1
1 1 0 0 0
则该矩阵的最后一列为(1 0 0 1 0)。给出了这一列,你的程序应该确定第一行为(0 0 0 1 1)。
输入: 输入第一行包含一个整数 N(0<=20000),表示二进制串的位数。第二行包含 N 个整数,表示已排序的矩阵的最后一列(从上到下)。
输出: 输出文件仅一行,包含 N 个整数,从左到右依次表示已排序的矩阵的第一行;若无解,则输出-1。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 这道题主要是一道找规律的题目
   因它是每次左移,所以每个数字都会出现在结尾所以它出现了几个1,整个二进制串就有几个1, 其次同理每个数字也会出现在开头. 所以按大到小排列最大的开头肯定是1. 现在来看一下样例,我们可以得出这样的结论①
   0xxx1
   0xxx0
   0xxx0
   1xxx1
   1xxx0
   这里的未知数都用xxx代替,但不表示xxx是相同的,因为它是从小到大排列的,所以往左移之后就是
   xxx10
   xxx00
   xxx00
   xxx11
   xxx01
   这样看起来是变了,但是实际上它的组合数不变,组合方式不变,只是排序方式变了
   我们再将它排序就会变回结论①
   但是我们不知道这些数字前面的数字是哪一个地方的
   这里说明一下
   结论①里最小的二进制串左移之后再排序,它肯定就变成了结论①里的第2串
   因为它的后面4个是最小的,其他的例如2号串左移之前的后4个组成的二进制串肯定比1号组成的大
   所以左移之后1就变成了2号
   注意,这里不是说1号变成2号,所以2号变成3号,3号变成4号....
   是说0开头的1号变成了0结尾的2号
   那么,1开头的4号就变成了1结尾的1号
   以此类推,排序,会发现每次都是这样子,左移之后排序都是这个顺序变化
   然而要推出所有数字要n-1次,经过变化后最后一行便就是在原来的基础上按这个方法来一遍
   即0开头的按顺序到了0结尾的去了,1开头的按顺序到了1结尾的去了
   如样例顺序变化
   0  1      1->2
   0  0      2->3
   0  0      3->5
   1  1      4->1
   1  0      5->4
   再按照这个变化方式输出一次
   第一个输出是1号对应的2号, 第二个输出是2号对应的3号, 第三个输出是3号对应的5号, 第四个输出是4号对应的1号, 第五个输出是5号对应的4号, 最后输出便是00011
*/

int zero=0,one=0,sumZero=0,nexts[20001],row[20001],n;
int main() {
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        scanf("%d",&row[i]);
        if(!row[i])
            sumZero++; // 记录0的数量,用于后续的记录1的起始位置和判定是否存在无解情况
    }
    one = sumZero;
    for(int i=1; i<=n; i++) {
        if(!row[i])
            nexts[++zero]=i; // 从第1个开始记录为0的下标位置
        else
            nexts[++one]=i;    // 从第sumZero+1个开始记录为1的下标位置
    }
    int k=1;    // 从第一个开始
    for(int i=1; i<=n; i++) {
        k = nexts[k];   // 获取第k个元素它在原数组的下标位置
        if(!row[k])
            sumZero--;   // 是0则递减,主要用于判断计算后行中0的个数是否与列中0的数量相同,判断解对不对
    }
    if(sumZero) { // 如果sumZero不为0,说明序列构成的0元素数量不同从而序列不对,所以不存在解
        printf("-1");
    } else { // 存在解,就继续从头找一遍输出
        k=1;
        for(int i=1; i<=n; i++) {
            k = nexts[k];
            printf("%d",row[k]);
            if(i<n)
                printf(" ");
        }
    }
    return 0;
}
  1. 二进制位不同的个数

对于两个非负整数 x 和 y,函数 f(x,y) 定义为 x 和 y 在二进制表示时,其对应位不同的个数。例如,f(2,3)=1,f(0,3)=2,f(5,10)=4。
现在给出一组非负整数 x 和 y,计算 f(x,y) 的值。
输入: 第一行:一个整数 T(0<T⩽100)​,表示有 T​ 组测试数据。
第 2 行 ~ T+1 行:每行输入两个正整数 x 和 y,(0⩽x,y⩽1000000)。两个整数之间有一个空格。
输出: 对每组测试数据,输出一行。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int f(int x,int y){
    int count=0;
    int n = x^y; //异或操作:二个位不相等时,结果为1,否则为0。
    while(n){ //如果十进制结果大于0说明有不同,计算二进制中1的个数
        if(n&1)count++;
        n>>=1;
    }
    return count;
}
int main(){
    int n=0,x=0,y=0;
    scanf("%d",&n);
    while(n-->0){
        scanf("%d %d",&x,&y);
        printf("%d\n",f(x,y));
    }
    return 0;
}

数列练习
205.数列项

非负数列项的第1项为0,第2项为1,后面的每项为其前面的 k(2≤k≤10) 项之和(若不存在前面的某个项,计算时以0表示)。
例如:k=3, 则数列项依次为:0,1,1(因前面的项不足3项,计算时以(0)表示,1+0+(0)=1),2,4,……
输入: 一行由一个空格分隔的正整数 k 和 n。
80%的数据点: 2≤k≤3,1≤n≤10
10%的数据点: 2≤k≤5,1≤n≤50
10%的数据点: 2≤k≤10,1≤n≤100
输出: 在一行中输出数列的第n项。

#include<iostream>
using namespace std;
int main() {
    int k,n;
    cin>>k>>n;
    int terms[k][100];//用int数组表示数列的每一项,terms每行保存数列的一项,共保存k个项(因为最多只会是前k项的和)
    for(int i=0; i<k; i++) {
        for(int j=0; j<100; j++) {
            terms[i][j]=0;
        }
    }
    terms[1][99]=1;//第二项为1
    if(n==1) {//第一项第二项直接输出
        cout << 0 << endl;
    } else if(n==2) {
        cout << 1 << endl;
    } else {
        //因为每一项或是前k项的和,或是前面若干项(不足k)与0的和,而terms数组的初值全部为0,
        //所以每次计算某项的值就是把数组表示的k项全部相加,最后的结果保存在最前面一项,
        //这里的最前面一项基于循环的思想(参考循环队列)
        for(int i=2; i<n; i++) { //从第三项开始依次计算到第n项
            int sum=0;
            int carry=0;
            for(int j=99; j>=0; j--) { //对k个数从右到左各位求和
                sum=0;
                for(int m=0; m<k; m++) { //k个数的相同位相加
                    sum+=terms[m][j];
                }
                sum+=carry;//再加上进位
                terms[i%k][j]=sum%10;//将sum取对k的余数保存到terms数组的i%k行中,因为这一行所代表的项已经没有用了
                carry=sum/10;//计算进位
            }
        }
        int first_non_zero_index=0;
        while(first_non_zero_index<100) { //找到第一个非0项
            if(terms[(n-1)%k][first_non_zero_index]!=0) {
                break;
            } else {
                first_non_zero_index++;
            }
        }
        if(first_non_zero_index==100) {
            cout<<0<<endl;
        } else {
            for(int i=first_non_zero_index; i<100; i++) {
                cout<<terms[(n-1)%k][i];
            }
            cout<<endl;
        }
    }
    return 0;
}
  1. 最长的等差数列

给定n(1≤n≤100)个数,从中找出尽可能多的数使得他们能够组成一个最长的等差数列。输出该最长等差数列的长度。
注意:当n=1时,构成长度为1的等差数列。
输入: 第 1 行:一个整数 T (1≤T≤10) 为测试数据组数。
每组测试数据按如下格式输入:
第 1 行:一个自然数n(1≤n≤100),表示数据的个数。
第2行到n+1:每行输入一个自然数。
输出: 对于每个问题,输出一行问题的编号(0 开始编号,格式:case #0: 等),然后在一行中输出按要求找到的最长等差数列的长度。

#include<bits/stdc++.h>
using namespace std;
int computeLength(int A [ ], int n) {
    // 如果数组长度小于等于2的时候,等差数列必定成立,所以直接返回大小
    if(n<=2)
        return n;
    int i, j, d, ans = 1;
    // 对数组内容做一次进行升序排序
    sort(A,A+n);
/* 使用在数组中存放map的方式来记录数据,采用自底向上的思想来更新构成等差数列的个数
    首先我们要后项减去前项,所以保证j>i
    d = A[j] - A[i]; d是第j项减去第i项的差值
    dp[j][d]表示的意思是A数组中第j个数字它参与差值为d的等差数列个数
    所以可以通过 dp[j][d] = dp[i][d] + 1;
    解释为: 数组中第j个数字它参与差值为d的等差数列个数 = 第i个数字它参与差值为d的等差数列个数 + 加上j这个数字的个数(也就是加 1 )
    为了记录最大等差数列个数,需要在每次更新中进行比较
    ans = max(ans, dp[j][d]);
    举例子: [ 1 , 2 ,3 ,4 ,5 ]
    计算完后的数据结构表示为
    [ {  } , { 1:1 } , { 1:2 , 2:1 } , { 1:3 , 2:1 , 3:1 } , { 1:4 , 2:2 , 3:1 ,4:1} ]
    { 1:4 , 2:2 , 3:1 ,4:1 } 是数组下标为4的数字5所包含的差值map集合
    map是以key:value的形式存储,1:4表示key为1的时候value为4
    5-1的差值为4,因此d=4,又因为数字5的下标为4,所以dp[4][4]=dp[3][4]+1
    因为dp[3]的map中不存在key为4的value,默认返回0,所以dp[3][4] = 0 , dp[4][4]=1   ==> 在dp[4]的map中生成{4:1}
    由于map<int, int>默认初始为0,所以答案需要加上1才是正确的数量
*/
    map<int, int> dp[n];
    for (j = 1; j < n; ++j) {
        for (i = 0; i < j; ++i) {
            d = A[j] - A[i];
            dp[j][d] = dp[i][d] + 1;
            ans = max(ans, dp[j][d]);
        }
    }
    return ans + 1;
}

int main(dex; i<100; i++)){
    int n=0,i=0,m=0;
    int A[101]= {0};
    cin>>n; // 给n赋值等价于 scanf("%d",&n);
    while(n-->0) {
       int j=0;
       cin >> m;
       while(j<m)
         cin >> A[j++];
         cout << "case #" << i << ":\n" << computeLength(A,j) << endl;
         i++;
    }
    return 0;
}

3002 泰波拿契数列的前74项:

在 Microsoft 和 Google 等众多名企的笔试或面试题中出现过一道题目,计算一个泰波拿契(tribonacci)数列。
泰波拿契数列的递归定义为:
T(0)=0
T(1)=T(2)=1
T(n)=T(n−1)+T(n−2)+T(n−3)(当n>2时)
根据定义,不难发现,数列的前几项为 0,1,1,2,4,7,13,24,44,81,149 等。
现在给定一个整数 n,计算 T(n) 的值。
输入: 第 1 行:一个整数 T (1≤T≤10) 为问题数。
接下来共 T 行。每行一个整数,表示 n(0≤n<74)。
输出: 对于每个问题,输出一行问题的编号(0 开始编号,格式:case #0: 等)。
然后对应每个问题在一行中输出 T(n)的值。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
    long long dp[75]= {0};
    int i=0,k=0,j=0,n=0;
    dp[0]=0;
    dp[1]=1;
    dp[2]=1;
    for(i=3; i<75; i++) {
        dp[i] = dp[i-3]+dp[i-2]+dp[i-1];
    }
    scanf("%d",&n);
    while(n-->0) {
        scanf("%d",&k);
        printf("case #%d:\n%lld\n",j,dp[k]);
        j++;
    }
    return 0;
}

多项式专题 2 2999 3028
练习: 2845符号方程求解 // 2944四元一次方程 // 2891多次函数 (选做) // 3006计算多项式的系数 HINT: Fermat’s little theorem – 假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p)

  1. 一元多项式乘法
    计算两个一元多项式的乘积。
    输入:每行两个多项式,以一个空格分隔,多项式格式为 anxn+…+a1x+a0。
    每行长度不超过100,0<n<50。
    输出: 每组数据一行,根据次数由高到低顺序输出两个多项式乘积的非零项系数,两个系数之间由一个空格分隔。

例如:
输入: x^2-3x+1 x^3
计算:( x2-3x+1)*(x3)
=x5-3x4+x^3
输出系数: 1 -3 1
1、输入多项式
2、解析多项式中的系数和指数
3、计算多项式乘法
4、输出乘积的系数

typedef struct {
    int dim; //记录多项式最高次方
    int coef[50]; //记录多项式各项的系数
} Polynome;

int main(){  
    Polynome poly1,poly2,result;//声明三个变量
    char s[512];
    scanf (%s”,s);//输入多项式1
    ReadPoly(s,&poly1);/*将多项式1各项系数指数最高次方存储在结构体中*/
    scanf (%s”,s);//输入多项式2
    ReadPoly(s,&poly2);//多项式2各项系数指数最高次方
    PolyMult(&poly1,&poly2,&result); /*多项式相乘将结果存放在result中*/
    output(&result);//输出result中的非零系数
    return 0;
}

声明和初始化结构体变量
(1)声明三个结构体
Polynome poly1,poly2,result;
(2)初始化结构体
void init(Polynome *poly,int dim){
int i;
poly->dim=dim;
for (i=0;i<=dim;i++)
poly->coef[i]=0;
}
解析多项式中的系数和指数

Polynome * ReadPoly (char s[],Polynome *poly){ 
	char *p;//定义字符指针
	int coef = 0,dim = 0;p = s;//指向字符串s
	p=ReadTerm(p,&coef,&dim);//解析多项式第一项系数和指数
	init(poly,dim);//初始化结构体poly
	poly->coef[dim] = coef;/*系数存放在下标为dim数组元素中*/
	while(*p){	//读取多项式后面的项,存储系数在结构体数组元素
	 p=ReadTerm(p,&coef,&dim);//解析多项式一项系数和指数
	  poly->coef[dim] = coef; 
     }
	return poly;
}
char * ReadTerm(char* p, int* coef, int* dim){
	*coef = 0; *dim = 0;int sign=1;
	if(*p == '-'){
		sign = -1;
		p++;
	}
	else if(*p == '+'){
	 	sign = 1;
		p++;
	}
	while(isdigit(*p)){	
		*coef = *coef*10+*p-'0';
		p++;
	}
	if(*p != 'x'){
		*coef *= sign;
		return p;
	}
}
if(*coef == 0)
	*coef = 1;
	*coef *= sign;
	p++;
	if(*p!='^'){
		*dim = 1;
		return p;
	}
	p++;
	*dim = 0;
	while(isdigit(*p)){
		*dim = *dim*10+*p-'0';
		p++;
	}
	return p;
}
void PolyMult(Polynome* poly1,Polynome * poly2,Polynome *result){
    int m=poly1->dim+poly2->dim;//计算最高次方的和
    init(result,m);//初始化result
    int i,j;
    for (i=0;i<=poly1->dim;i++){
        for (j=0;j<=poly2->dim;j++){
            result->coef[i+j]=result->coef[i+j]+poly1->coef[i]*poly2->coef[j];
        }
    }
}
void output(Polynome *result){
/*由于要输出有空格分割的非零系数,最后一个系数结束不能有空格,因此将非零系数另外放在一个数组,单独输出最后一个元素。*/
   int i,j,out[100];
   for (i=0,j=0;i<=result->dim;i++)
    	if (result->coef[i]!=0){
			out[j]=result->coef[i];
			j++;
		}
      for (j=j-1;j>0;j--) 
			printf("%d ",out[j]);
      printf("%d",out[j]);
}

2999.计算多项式的系数

给定一个多项式 (a×x+b×y)k,计算多项式展开后 xn×ym项的系数。
输入: 第 1 行:一个整数 T (1≤T≤10) 为问题数。
接下来共 T 行。每行 5 个整数,分别为 a,b,k,n,m,整数之间由一个空格分隔。
0≤k≤1000,0≤n,m≤k,且n+m=k,0≤a,b≤1000000
输出: 对于每个问题,输出一行问题的编号(0 开始编号,格式:case #0: 等)。
然后对应每个问题在一行中输出一个整数,表示所求的系数(这个系数可能很大,输出对 10007 取模后的值)。
因此,我们可以定义个静态二维数组dp[n][m]存放xiyj 的系数。
当k=i+j=0时 dp[0][0]=1;
当k>0时
当i0时, dp[i] [j]= b*dp[i][j-1]
当j
0时, dp[i] [j]= adp[i-1][j]
否则,dp[i] [j]=a
dp[i-1] [j]+b* dp[i] [j-1]
例如:当j==0时,x1000y0系数=a*(x999y0)的系数,
即dp[1000][0]=a*dp[999][0]

问题:数值范围
0≤k≤1,000,0≤n,m≤k,
n+m=k,0≤a,b≤1,000,000
例如:k=1000, a=b=1000000
由于x1000y0系数为a1000, a1000将达到106000,这是一个很大的数
数值范围的解决方法
使用模运算的性质:(ab)%N = (a%N * b%N)%N, 由于N=10007,因此计算的中间结果用int表示就行了。
因此,根据模运算性质,我们在输入a,b时和计算dp[i][j]都做了%N运算
f(n,m,a%N,b%N));
dp[i][j] = b
dp[i][j-1]%N;
dp[i][j] = adp[i-1][j]%N;
dp[i][j] = (a
dp[i-1][j]+b*dp[i][j-1])%N;

void solve(){
	int a,b,n,m;
	scanf("%d%d%*d%d%d",&a,&b,&n,&m);
	printf("%d\n",f(n,m,a%N,b%N));
} 
int f(int n,int m,int a, int b){
   static int dp[M][M]={1},i,j;
  for (i=0;i<=n;i++) for (j=0;j<=m;j++){
     if (i+j)
     if (i==0)   dp[i][j] = b*dp[i][j-1]%N;
     else if (j==0)  dp[i][j] = a*dp[i-1][j]%N;
     else   dp[i][j] = (a*dp[i-1][j]+b*dp[i][j-1])%N;
  }
  return dp[n][m];
}

3028 构造多项式

给你 9 个整数,分别是 x8 到 x0 的系数,请按照多项式的一般构造规则合理构造。构造规则如下:
(1) 多项式的项必须按其指数从高到低排列。
(2) 指数必须跟在符号 ^ 后显示。但指数为 1 时,则不需要显示指数 1。
(3) 常数项不显示变量 x,只显示系数。
(4) 只显示系数不为 0 的项,如果系数全为 0,则需要显示常数项 0。
(5) 系数是 1,指数不为 0 时,则不显示系数 1。而系数是 1,指数为 0 时,系数的 1 需要显示。
(6) 系数是−1,指数不为 0 时,则只显示负号,不显示 1。而系数是−1,指数为 0 时,则显示−1。
输入: 第 1 行:一个整数 T (1≤T≤10) 为问题数。
接下来有 T 行,对应每个问题有 1 行,每行有 9 个整数,整数之间用空格分隔。这 9 个整数的取值范围为 [−1000,1000]。
输出: 对于每个问题,输出一行问题的编号(0 开始编号,格式:case #0: 等)。
然后对应每个问题在一行中输出对应的多项式。

解题思路
1、循环输入9个整数,循环变量从8开始到0;
2、判断是否为首项,记录首项位置;
3、如果首项为0,并且i==0,说明仅有常数项,输出该整数,包括0。
3、如果首项位置不为0并且绝对值非0的情况下:
如果a>0且非首项输出+号;
如果a<0, 输出-号;
4、如果a的绝对值不为1或者i=0,输出a的绝对值
否则不输出;
5、如果i>0,输出x;
6、如果i>1,输出^i。

 void solve() {
 	int i,a,first=0,flag=0;//引入flag判断是否为首项,first记录首项非零是第几项
 	for (i=8;i>=0;i--){
     scanf("%d",&a);
     if (a&&!flag) {
			flag=1,first=i; //如果非0,flag为0,说明该项是首项
	  }
     if (first==0 && i==0)  printf(%d”,a);//如果是仅有常数项输出
     if (first!=0 &&a!=0){
         if (a<0) 	printf("-");
         if (a>0 && i!=first) 	printf("+");
         if ((int)fabs(a)!=1||i==0) 	printf ("%d",(int)fabs(a));
         if (i>0)	 printf("x");
         if (i>1) 	printf("^%d",i);
	  }
	}
	printf("\n");
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值