特殊问题 用两位long long 代替大数运算

来源:互联网 发布:java 重写 重载 编辑:程序博客网 时间:2024/05/10 16:10

特殊问题 用两位long long 代替大数运算

原问题

矩阵取数【问题描述】
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均
为非负整数。游戏规则如下:
1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素值*2i,
其中i 表示第i 次取数(从1 开始编号);
4. 游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分

需要解决的大数运算

每次取一个数X(0X1000)
总得分为 前面累积的得分 +X2i (1i80)
每次得分范围为 不超过10002801028
最多取80次计算最后得分的范围为 答案 1030

思路

用 long long a[2] 存放 表示已经积累的分数
用 long long b[2] 存放 上次的2i
用 long long c[2] 存放这次的 分数

计算

  • 1.算出此次得分
b[1]=b[1]*2;b[0]=b[0]*2;if(b[0]>Limit){    b[1]++;           //这里进位只可能是1    b[0]%=Limit;}//b[2] 等于这次的2^ic[1]=b[1]*x;c[0]=b[0]*x;if(c[0]>Limit){    c[1]+=c[0]/Limit; //这里进位有可能大于1    c[0]%=Limit; }//乘上x
  • 1.加到总得分
a[1]+=c[1];a[0]+=c[0];if(a[0]>limit){    a[1]++;         //这里进位只可能是1    a[0]=a[0]%Limit;}

常数LImit应该为多少

64位的a[1] 可以设定a[1]范围为 0a[1]1019
至于a[0] 假设 0a[0]10i
我们需要 19+i30 (两个long long 能表示的范围要符合题目需要)
并且 10i10001019 (确保最坏情况不溢出)
所以 11i16
至于Limit 应该取 10i

代码

/*【问题描述】帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;2. 每次取走的各个元素只能是该元素所在行的行首或行尾;3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素值*2i,其中i 表示第i 次取数(从1 开始编号);4. 游戏结束总得分为m次取数得分之和。帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。输入描述 Input Description第1行为两个用空格隔开的整数n和m。第2~n+1 行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。输出描述 Output Description输出 仅包含1 行,为一个整数,即输入矩阵取数后的最大得分。*/#include<cstdio>#include<iostream>#include<string.h>#include<string>#include<cmath>#pragma warning(disable:4996)using namespace std;class bign{public:    long long high;    long long low;    friend ostream& operator<<(ostream& out, bign &a)    {        if (a.high)        {            out << a.high;            printf("%06d", a.low / 1000000);            printf("%06d", a.low % 1000000);        }        else        {            cout << a.low;        }        return out;    }};int n, m;int matrix[81][81];bign dp[81][81][81];bign two[81];       //存2^ilong long Limit = 1000000000000;//10^12bign add(bign a, bign b){    a.high += b.high;    a.low += b.low;    if (a.low > Limit)    {        a.high++;        a.low %= Limit;    }    return a;}bign mul(bign a, int b)//b<=1000{    a.high *= b;    a.low *= b;    if (a.low > Limit)    {        a.high += a.low / Limit;        a.low %= Limit;    }    return a;}bool ismax(bign a, bign b){    if (a.high > b.high || (a.high == b.high&& a.low > b.low))return 1;    return 0;}int main(){    //n行m列    cin >> n >> m;    int i, j;    for (i = 1; i <= n; i++)    {        for (j = 1; j <= m; j++)        {            cin >> matrix[i][j];        }    }    memset(dp, 0, sizeof(dp));    two[1].high = 0;    two[1].low = 2;    for (i = 2; i <= m; i++) //计算2^i    {        two[i] = mul(two[i - 1], 2);        //cout << two[i] << endl;    }    for (i = 1; i <= n; i++) //计算每一行    {        int head;        for (head = m; head >=1; head--)        {            int end;            for (end = head; end <=m; end++)            {                int NumberOfTimes = m-(end - head + 1)+1;                if (head == end)                {                    dp[i][head][end] = mul(two[NumberOfTimes], matrix[i][head]);                }                else                {                    bign a = add(dp[i][head + 1][end],mul(two[NumberOfTimes],matrix[i][head]));                    bign b = add(dp[i][head][end - 1], mul(two[NumberOfTimes], matrix[i][end]));                    dp[i][head][end] = ismax(a, b) ? a : b;                }            }        }    }    bign sum = bign{ 0,0 };    for (i = 1; i <= n; i++)//累加每一行    {        sum = add(sum, dp[i][1][m]);    }    cout << sum;    return 0;}
0 0
原创粉丝点击