国际大学生程序设计竞赛例题_1.2 求和

题目大意:
不计进位的加法,进制范围:2到16
例如:
55 67
十进制:55 add 67=12
二进制:110111 add 1001100=1111011=123

输入:
2 10 //两个区域,十进制加
3 6
9 15
输出:
从3到6 加上 从9到15的和

解答:

#include <iostream>
using namespace std;

#define MAX_SCALE 16 //最大进制数
#define LEN 32 //最大位数

unsigned int a[LEN],b[LEN]; //加数与被加数给位上的数

void add(unsigned int& x, unsigned int y, int m) //m进制不进位加法
{
x = (x+y)%m;
}

void calc(unsigned int x, unsigned int m, unsigned int b[]) //求m进制下sum(0:x),结果存储在b
{
int i,j,k;
for(i=0; i<LEN; i++) b[i]=0;
if(x==0) return; //结果为0

unsigned int c[LEN][MAX_SCALE];//c[i][j]:第i为上数字j出现的次数
unsigned int d[LEN]; //d[i]为m^i
unsigned int digit[LEN];//digit[i]为x的第i为数字

unsigned int temp=x; //计算digit[]数组
unsigned int nDigit=0; //保存位数
while(temp>0)
{
digit[nDigit++] = temp%m;
temp /= m;
}

//计算d[]数组
d[0]=1;
for(i=1; i<nDigit; i++)
d[i] = d[i-1]*m;

//初始化c[][]数组
for(i=nDigit-1; i>=0; i--)
for(j=0; j<MAX_SCALE; j++)
c[i][j] = 0;

//由高位到低位计算c数组
for(i=nDigit-1; i>=0; i--)
{
for(j=0; j<digit[i]; j++)
add(c[i][j], d[i], m); //数字0-digit[i-1],出现了M^i次.
add(c[i][digit[i]], x%d[i]+1, m); //数字digit[i],出现了x%(M^i)+1次

for(j=i-1; j>=0; j--)
for(k=0; k<m; k++)
add(c[j][k], digit[i]*d[i-1], m); //低位上每个数字出现digit[i]*(M^(i-1))次
}

for(i=0; i<nDigit; i++)
{
b[i]=0;
for(j=0; j<m; j++)
add(b[i], c[i][j]*j, m);
}
}
int main()
{
freopen("1.2.in", "r", stdin);
int T;//数据组数
int n,m;//区间数与进制数
unsigned int x,y,ans;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
memset(a, 0, sizeof(a)); //保存最后结果
while(n--)
{
scanf("%u%u", &x,&y); //输入区间[x,y]
calc(y, m, b); //计算sum(0:y)
for(int i=0; i<LEN; i++)
a[i] = (a[i]+b[i])%m; //实际上就是把b[i]赋值给a[i]
if(x>0)
{
calc(x-1, m, b); //计算sum[0:x-1]
for(int i=0; i<LEN; i++)
a[i] = (a[i]-b[i]+m)%m; //sum[x:y]=sum[0:y]-sum[0:x-1]
}
}
ans = 0; //保存十进制结果
for(int i=LEN-1; i>=0; i--)
ans = ans*m+a[i];
printf("%u\n",ans);
}
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值