蓝桥杯 历届试题 矩阵翻硬币

很夸张的题目
我从头到尾题目意思都理解错了
没错 这句话暴露出我看了题解
这道题就是个大数开根号 因为第x行只能被x的约数xi影响 本来最后是正面朝上的 现在需要反面(逆推回去)
就必须要翻奇数次
也就是求一个数 奇数X=xi*yi (xi和yi分别表示某个数的约数) 然后符合这样的数有什么条件
首先 xi yi 也都必须是奇数 别给我说其中一个是偶数还会满足条件
然后 困难来了 什么数的约数会有奇数个
不知道就先打表play

 1. 1
 2. 2
 3. 2
 4. 3
 5. 2
 6. 4
 7. 2
 8. 4
 9. 3
 10. 4
 11. 2
 12. 6
 13. 2
 14. 4
 15. 4
 16. 5

大家可以找一找 有奇数个 约数的数有什么共同特征?
1 4 9 16
当然 你也可以继续写下去 会发现 这是个完全平方数
根据数据 这道题就是个大数开方题了

大数怎么开方?
根据一个牛顿b进定理(不知道名字是不是对的……)
奇数开方的结果是(n>>1 |1) 位,而偶数的结果是(n>>1) 位
证明去问牛顿

#include  
#include  

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()) 
        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; 
} 

string sqrt_(string str) { 
    int len = str.length(); 
    int i, j, len1 = len >> 1; 
    string str1 = ""; 
  ///假如一个数有偶数位n,那么这个数的方根有n/2位;如果n为奇数,那么方根为(n+1)/2位
    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';
            /// 第三个参数为第一个串的尾零个数 
            if (str_bigger(str1 * str1, str, (len1-(i+1)) << 1)){ 
                --str1[i]; break; 
            }
        } 
    }
    return str1; 
} 

int main(){
    string a, b; 
    while (cin >> a >> b){
        cout << sqrt_(a) * sqrt_(b) << endl; 
    }
    return 0; 
} 

你可能感兴趣的:(ACM_模拟,ACM_数论,蓝桥杯_)