进制转换练习
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;
}
- 二进制位不同的个数
对于两个非负整数 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;
}
- 最长的等差数列
给定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)
- 一元多项式乘法
计算两个一元多项式的乘积。
输入:每行两个多项式,以一个空格分隔,多项式格式为 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]
当j0时, 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] = bdp[i][j-1]%N;
dp[i][j] = adp[i-1][j]%N;
dp[i][j] = (adp[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");
}