hdu 奥运(矩阵快速幂+等比数列快速求和+数论)

奥运

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2457    Accepted Submission(s): 614


Problem Description
北京迎来了第一个奥运会,我们的欢呼声响彻中国大地,所以今年的奥运金牌 day day up!
比尔盖兹坐上鸟巢里,手里摇着小纸扇,看的不亦乐乎,被俺们健儿的顽强拼搏的精神深深的感动了。反正我的钱也多的没地方放了,他对自己说,我自己也来举办一个奥运会,看谁的更火。不过他的奥运会很特别:
1 参加人员必须是中国人;
2 至少会加法运算(因为要计算本人获得的金牌数)
他知道中国有很多的名胜古迹,他知道自己在t1 到 t2天内不可能把所有的地方都玩遍,所以他决定指定两个地方v1,v2,如果参赛员能计算出在t1到t2天(包括t1,t2)内从v1到v2共有多少种走法(每条道路走需要花一天的时间,且不能在某个城市停留,且t1=0时的走法数为0),那么他就会获得相应数量的金牌,城市的总数<=30,两个城市间可以有多条道路
,每条都视为是不同的。
 

Input
本题多个case,每个case:
输入一个数字n表示有n条道路 0<n<10000
接下来n行每行读入两个数字 p1,p2 表示城市p1到p2有道路,并不表示p2到p1有道路 (0<=p1,p2<2^32)
输入一个数字k表示有k个参赛人员
接下来k行,每行读入四个数据v1,v2,t1,t2 (0<=t1,t2<10000)
 

Output
对于每组数据中的每个参赛人员输出一个整数表示他获得的金牌数(mod 2008)
 

Sample Input
  
  
6 1 2 1 3 2 3 3 2 3 1 2 1 3 1 2 0 0 1 2 1 100 4 8 3 50
 

Sample Output
  
  
0 1506 0
 

Source
题目分析:
根据离散数学得到,A^x表示在x天内能到达某点的方案数,是一个前缀和,所以在求t1-t2,只需求取t2减去t1-1,因为求的是前缀和,是一个等比数列,所以可以利用分枝法优化,logn的求取,
就是利用提公因式的方法,每次提出a^ (p/2-1)的公因数,得到两个相等的相加的和式,将原式递归处理
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <map>
#define MAX 37
#define MOD 2008

using namespace std;

typedef long long LL;

int n,k,cnt;
map<LL,int> mp;

struct Matrix 
{
    LL a[MAX][MAX];
    Matrix ( )
    {
        memset ( a , 0 , sizeof ( a ) );
    }
};

Matrix multi ( Matrix m1 , Matrix m2 )
{
    Matrix ret;
    for ( int i = 1 ; i < cnt ; i++ )
        for ( int j = 1 ; j < cnt ; j++ )
            if ( m1.a[i][j] )
                for ( int k = 1 ; k < cnt ; k++ )
                    ret.a[i][k] = ( ret.a[i][k] + m1.a[i][j]*m2.a[j][k]%MOD )%MOD;
    return ret;
}

Matrix quick ( Matrix m , int n )
{
    Matrix ret;
    for ( int i = 1 ; i < cnt ; i++ )
        ret.a[i][i] = 1;
    while ( n )
    {
        if ( n&1 ) ret = multi ( ret , m );
        m = multi ( m , m );
        n >>= 1;
    }
    return ret;
}

Matrix add ( Matrix m1 , Matrix m2 )
{
    Matrix ret;
    for ( int i = 1 ; i < cnt ; i++ )
        for ( int j = 1 ; j < cnt ; j++ )
            ret.a[i][j] = ( m1.a[i][j] + m2.a[i][j] )%MOD;
    return ret;
}

Matrix cal ( Matrix& m , int k )
{
    if ( k <= 0 ) return quick ( m , 0 );
    int b = (k+1)/2;
    Matrix temp = cal ( m , b-1 );
    Matrix ret = add ( temp , multi ( quick ( m , b ) , temp ) );
    if ( k%2 == 0 ) ret = add ( ret , quick ( m , k ) );
    return ret;
}

void print ( Matrix m )
{
    for ( int i = 1 ; i < cnt ; i++ )
    {
        for ( int j = 1 ; j < cnt ; j++ )
            printf ( "%lld " , m.a[i][j] );
        puts("");
    }
}

int main ( )
{
    LL u,v;
    int v1, v2, t1, t2;
    while ( ~scanf ( "%d" , &n ) )
    {
        cnt = 1;
        Matrix ans;
        mp.clear();
        for ( int i = 0 ; i < n ; i++ )
        {
            scanf ( "%lld%lld" , &u , &v );
            if ( !mp[u] ) mp[u] = cnt++;
            if ( !mp[v] ) mp[v] = cnt++;
            u = mp[u] , v = mp[v];
            ans.a[u][v]++;
        }
       // print ( ans );
        scanf ( "%d" , &k );
        while ( k-- )
        {
            scanf ( "%d%d%d%d" , &v1 , &v2 , &t1 , &t2 );
            int u = mp[v1] , v = mp[v2];
            if ( !u || !v )
            {
                puts ("0");
                continue;
            }
            Matrix m1 = cal ( ans , t1-1 );
            Matrix m2 = cal ( ans , t2 );
            printf ( "%lld\n" , (m2.a[u][v] - m1.a[u][v]+MOD)%MOD );
        }
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值