首页 > 代码库 > HPU1288 矩阵翻硬币 【大数】

HPU1288 矩阵翻硬币 【大数】

1288: 矩阵翻硬币

时间限制: 10 Sec  内存限制: 128 MB
提交: 1  解决: 1
[提交][状态][讨论版] [Edit]

题目描述

问题描述  小明先把硬币摆成了一个 n 行 m 列的矩阵。   随后,小明对每一个硬币分别进行一次 Q 操作。   对第x行第y列的硬币进行 Q 操作的定义:将所有第 i*x 行,第 j*y 列的硬币进行翻转。   其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。   当小明对所有硬币都进行了一次 Q 操作后,他发现了一个奇迹——所有硬币均为正面朝上。   小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。   聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。

输入

多组输入,每行两个正整数 n m,其中n、m <= 10^1000(10的1000次方),含义见题目描述。

输出

输出一个正整数,表示最开始有多少枚硬币是反面朝上的。

样例输入

2 3

样例输出

1

先考虑一维的情况,若第x个数被翻转奇数次,那么它的约数必定有奇数个,而只有平方数的约数是奇数个,那么也就是说对于一维的情况只有x为平方数时它才被翻转奇数次,对于二维的情况(x,y)点被翻转情况是x的约数*y的约数为该点翻转的次数,只有当这个数为奇数时,该点才被翻转奇数次,而奇数*奇数==奇数,也就是说x和y必须都是平方数才行,那么答案出来了,一个n行m列的矩阵在行上有sqrt(n)个平方数,在列上有sqrt(m)个平方数,组合出来的平方点对一共是sqrt(n)*sqrt(m).由于是大数,需要用字符串存储,大数相乘和大数开方直接用模板。

#include <iostream> 
#include <string> 
  
using namespace std; 
  
/* 大数相乘 */
string operator * (string str1, string str2) { 
    string result = ""; 
    int len1 = str1.length(); 
    int len2 = str2.length(); 
    int num[1002] = {0}; // 此处用来临时保存两数相乘的结果 
    int i, j; 
  
    if (!len1 || !len2) return "0"; // 处理空指针 
  
    for (i = 0; i < len1; ++i) { 
        for (j = 0; j < len2; ++j) 
            num[len1-1-i + len2-1-j] += (str1[i] - '0') * (str2[j] - '0'); 
    } 
  
    for (i = 0; i < len1 + len2; ++i) { 
        num[i+1] += num[i] / 10; 
        num[i] %= 10; 
    } 
  
    for (i = len1 + len2 - 1; !num[i]; --i); 
    for ( ; i >= 0; --i) 
        result += num[i] + '0'; 
      
    if (result.length() == 0) result = "0"; 
    return result; 
} 
  
bool str_bigger(string str1, string str2, int zeros) { 
    int len1 = str1.length(); 
    int len2 = str2.length(); 
    int i, j; 
  
    if (len1 + zeros < len2) return false; 
    else if (len1 + zeros > len2) return true; 
  
    for (i = 0; i < len1; ++i) { 
        if (str1[i] > str2[i]) return true; 
        else if (str1[i] < str2[i]) return false; 
    } 
  
    return false; 
} 
  
/* 返回sqrt(n)的取整结果 */
string sqrt_large(string str) { 
    int len = str.length(); 
    int i, j, len1 = len >> 1; 
    string str1 = ""; 
  
    if (len & 1) ++len1; // 长度为奇数,例如121=11*11 
      
    for (i = 0; i < len1; ++i) { 
        str1 += '0'; 
        for (j = 0; j < 10; ++j) { 
            str1[i] = j + '0'; // attention 
            // 第三个参数为第一个串的尾零个数 
            if (str_bigger(str1 * str1, str, (len1-(i+1)) << 1)) { 
                --str1[i]; break; 
            } 
        } 
    } 
  
    return str1; 
} 
  
int main() { 
    // freopen("stdin.txt", "r", stdin); 
    // freopen("stdout.txt", "w", stdout); 
    string a, b; 
    while (cin >> a >> b) { 
        cout << sqrt_large(a) * sqrt_large(b) << endl; 
    } 
    return 0; 
} 


HPU1288 矩阵翻硬币 【大数】