ZOJ 3857 Hypersphere 构造 + 矩阵快速幂

ZOJ 3857 Hypersphere

2013年长沙网络赛的一道题, 恩第一眼根本没看懂题意, 后来才知道这个题是给定K和L两个正整数之后求
(L+L(L1))Kmod K 的值前面一部分是向下取整

这个题首先 直接通过快速幂来求的, 抛开浮点数误差不谈, K的值可能很大, 直接计算前面想下去整部分的话double应该都存不下

而这个题神奇的地方就在这里, 通过巧妙的共轭的构造使得原本计算的浮点数变成了整数
构造数列 a 使得
a[t]=(L+L(L1))t+(LL(L1))t
那么 a[t] 的左半部分是我们需要的, 而对于右半部分, 可以发现对于L >= 1, 这是一个最大为1, 最小是0.5的数的t次方, 证明如下:
(LL(L1))=L(LL1)=LL+L1=11+11L
当L = 1时最大时1, L趋近于无穷大是其值为0.5, 所以右半部分一定是一个最大为1的数, 并且可以趋近至0
另外一个巧妙的地方就是, 这个数列a的每一项都是整数, 这个是数列中的一个结论, 首先二次方程的两个根是
x1=L+L(L1),x2=LL(L1)
可以发现
x1+x2=2L,x1x2=L
这是方程 x22Lx+L=0 的两个根于是通过
a[0]=2,a[1]=2L , 且有方程 a[i+1]2La[i]+La[i1]=0 得到所有的数列a中的数(这个数列递推什么的是高中数学竞赛里的内容吧..)
因为数列a中的数都是整数, 可以在递推的同时进行取模操作, 另外由于最后只需要左边的项, 而右边那项的值不超过1, 只需要将最后得到的结果减去1就可以了, 相当于浮点数向下取整的操作
至于数列a的转移方程, 很明显是线性转移, 通过矩阵快速幂来加速计算即可, 例如构造矩阵转移: [anan1][2LL10]=[an+1an]

代码如下:

/* * Author: Gatevin * Created Time: 2015/7/17 13:27:13 * File Name: ZOJ3857.cpp */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

lint K, L;

struct Matrix
{
    lint a[4][4];
    Matrix()
    {
        for(int i = 0; i < 2; i++)
            for(int j = 0; j < 2; j++)
                a[i][j] = i == j ? 1 : 0;
    }
    lint* operator [] (int i)
    {
        return a[i];
    }
};

Matrix operator * (Matrix &m1, Matrix &m2)
{
    Matrix ret;
    for(int i = 0; i < 2; i++)
        for(int j = 0; j < 2; j++)
        {
            ret[i][j] = 0;
            for(int k = 0; k < 2; k++)
                ret[i][j] = (ret[i][j] + m1[i][k]*m2[k][j]) % K;
        }
    return ret;
}

Matrix quick(Matrix base, int pow)
{
    Matrix I;
    while(pow)
    {
        if(pow & 1) I = I*base;
        base = base*base;
        pow >>= 1;
    }
    return I;
}

int main()
{
    while(~scanf("%lld %lld", &K, &L))
    {
        Matrix A;
        A[0][0] = 2*L % K;
        A[0][1] = 1;
        A[1][0] = (L % K == 0) ? 0 : K - (L % K);
        A[1][1] = 0;
        A = quick(A, K - 1);
        lint ans = (2*L*A[0][0]) % K + (2*A[1][0]) % K;
        ans = (ans - 1 + K) % K;
        printf("%lld\n", ans);
    }
    return 0;
}

你可能感兴趣的:(Math,Matrix,ZOJ-3857)