HDU 2254解题报告

奥运

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


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
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   2256  2294  3117  2842  3519 
 
不得不说,这是我所做过的矩阵题目中比较神的一道。不是题的难度大,而是数据比较神奇。把int改成long long就过不了。坑了一下午一直找不到WA的原因,后来才发现是题的问题。在图论中,关系矩阵的n次方,表示经过k步可以到达的状态。与floyd算法的dp思想有关。因而可以用矩阵快速幂求解。在本题中设关系矩阵为A,则题目所求为A^(t1)+A^(t1+1)+……+A^(t2)的值。而A^0=E。也就是任意不同的两个点之间经过0步的走法是0种。

       此外还需要说的就是本题中要用map对点进行离散化,还要考虑两个点之间可能有重边,而我们计算方法数的时候要将他们算成是不同的。各种坑爹数据。。醉的一阵一阵的。。

       下面写出几种不同的参考代码以及由于题目数据有问题而导致过不了的代码。

       AC代码1:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<iomanip>
#include<utility>
#define pb push_back
#define mp make_pair
#define CLR(x) memset(x,0,sizeof(x))
#define _CLR(x) memset(x,-1,sizeof(x))
#define REP(i,n) for(int i=0;i<n;i++)
#define Debug(x) cout<<#x<<"="<<x<<" "<<endl
#define REP(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=l;i<r;i++)
#define RREP(i,l,r) for(int i=l;i>=r;i--)
#define rrep(i,l,r) for(int i=1;i>r;i--)
#define read(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<11
using namespace std;

int n,k,num;
const int mod=2008;
struct mat
{
    int d[33][33];   //这里用int型,可以AC
} A,E;
map<int,int>m;

mat multi(mat a,mat b)
{
    mat ans;
    REP(i,1,num)
    {
        REP(j,1,num)
        {
            ans.d[i][j]=0;
            REP(k,1,num)
            if(a.d[i][k]&&b.d[k][j])
                ans.d[i][j]=(ans.d[i][j]+(ll)a.d[i][k]*b.d[k][j])%mod;  //由于是int型,防止溢出,强制转换
        }
    }
    return ans;
}

mat add(mat a,mat b)
{
    mat ans;
    REP(i,1,num)
        REP(j,1,num)
            ans.d[i][j]=(a.d[i][j]+b.d[i][j])%mod;
    return ans;
}

mat quickmulti(mat a,int n)   //矩阵快速幂
{
    if(n==0) return E;
    if(n==1) return a;
    mat ans=E;
    while(n)
    {
        if(n&1)
        {
            n--;
            ans=multi(ans,a);
        }
        else
        {
            n>>=1;
            a=multi(a,a);
        }
    }
    return ans;
}

mat solve(mat a,int n)       //二分矩阵多项式
{
    if(n==1) return a;
    mat ans=solve(a,n/2);
    mat res=add(ans,multi(quickmulti(a,n/2),ans));
    if(n%2==1) res=add(res,quickmulti(a,n));
    return res;
}

int main()
{
    CLR(E.d);
    rep(i,0,33)
    E.d[i][i]=1;
    while(~scanf("%d",&n))
    {
        CLR(A.d);
        m.clear();
        num=0;     //num计算的是实际的点数
        REP(i,1,n)
        {
            int p1,p2;
            scanf("%d%d",&p1,&p2);
            if(!m[p1]) m[p1]=++num;
            if(!m[p2]) m[p2]=++num;
            ++A.d[m[p1]][m[p2]];  //考虑重边,所以要用++
        }
        scanf("%d",&k);
        rep(i,0,k)
        {
            int v1,v2,t1,t2;
            scanf("%d%d%d%d",&v1,&v2,&t1,&t2);
//            if(!m[v1]||!m[v2])   //此时加不加这个判断都能AC,另一种解法不加就WA
//            {
//                printf("0\n");
//                continue;
//            }
            v1=m[v1],v2=m[v2]; //转换成离散化后对应的点的编号
            if(!t1) t1++;  //t1=0的时候不用考虑
            if(t1<=t2)  
            {
                mat ans=solve(A,t2-t1+1);
                mat ans1=quickmulti(A,t1-1);
                ans=multi(ans,ans1);
                printf("%d\n",ans.d[v1][v2]%mod);  //这里用%d输出就能AC
            }
            else
                printf("0\n");
        }
    }
}


同样的代码,只是把矩阵里面数组的类型改成long long,最终用%I64d输出就会WA。坑爹不偿命。。 抓狂

WA的代码:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<iomanip>
#include<utility>
#define pb push_back
#define mp make_pair
#define CLR(x) memset(x,0,sizeof(x))
#define _CLR(x) memset(x,-1,sizeof(x))
#define REP(i,n) for(int i=0;i<n;i++)
#define Debug(x) cout<<#x<<"="<<x<<" "<<endl
#define REP(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=l;i<r;i++)
#define RREP(i,l,r) for(int i=l;i>=r;i--)
#define rrep(i,l,r) for(int i=1;i>r;i--)
#define read(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<11
using namespace std;

int n,k,num;
const int mod=2008;
struct mat
{
    ll d[33][33];
}A,E;
map<int,int>m;

mat multi(mat a,mat b)
{
    mat ans;
    REP(i,1,num)
    {
        REP(j,1,num)
        {
            ans.d[i][j]=0;
            REP(k,1,num)
                if(a.d[i][k]&&b.d[k][j])
                    ans.d[i][j]=(ans.d[i][j]+(ll)a.d[i][k]*b.d[k][j])%mod;
        }
    }
    return ans;
}

mat add(mat a,mat b)
{
    mat ans;
    REP(i,1,num)
        REP(j,1,num)
          ans.d[i][j]=(a.d[i][j]+b.d[i][j])%mod;
    return ans;
}

mat quickmulti(mat a,int n)
{
    if(n==0) return E;
    if(n==1) return a;
    mat ans=E;
    while(n)
    {
        if(n&1)
        {
            n--;
            ans=multi(ans,a);
        }
        else
        {
            n>>=1;
            a=multi(a,a);
        }
    }
    return ans;
}

mat solve(mat a,int n)
{
    if(n==1) return a;
    mat ans=solve(a,n/2);
    mat res=add(ans,multi(quickmulti(a,n/2),ans)); 
    if(n%2==1) res=add(res,quickmulti(a,n));
    return res;
}

int main()
{
    CLR(E.d);
    rep(i,0,33)
      E.d[i][i]=1;
    while(~scanf("%d",&n))
    {
        CLR(A.d);
        m.clear();
        num=0;
        rep(i,0,n)
        {
            int p1,p2;
            read(p1);read(p2);
            if(!m[p1]) m[p1]=++num;
            if(!m[p2]) m[p2]=++num;
            ++A.d[m[p1]][m[p2]];
        }
        scanf("%d",&k);
        rep(i,0,k)
        {
            int v1,v2,t1,t2;
            scanf("%d%d%d%d",&v1,&v2,&t1,&t2);
            if(!t1) t1++;
            v1=m[v1],v2=m[v2];
            if(t1<=t2)
            {
                mat ans=solve(A,t2-t1+1);
                mat m1=quickmulti(A,t1-1);
                ans=multi(ans,m1);
                printf("%I64d\n",ans.d[v1][v2]);
            }
            else
                printf("0\n");
        }
    }
}

AC代码2:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<iomanip>
#include<utility>
#define pb push_back
#define mp make_pair
#define CLR(x) memset(x,0,sizeof(x))
#define _CLR(x) memset(x,-1,sizeof(x))
#define REP(i,n) for(int i=0;i<n;i++)
#define Debug(x) cout<<#x<<"="<<x<<" "<<endl
#define REP(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=l;i<r;i++)
#define RREP(i,l,r) for(int i=l;i>=r;i--)
#define rrep(i,l,r) for(int i=1;i>r;i--)
#define read(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<11
using namespace std;

int n,k,num;
const int mod=2008;
struct mat
{
    int d[33][33];
} A,E;
map<int,int>m;

mat multi(mat a,mat b)
{
    mat ans;
    rep(i,0,num)
    {
        rep(j,0,num)
        {
            ans.d[i][j]=0;
            rep(k,0,num)
                if(a.d[i][k]&&b.d[k][j])
                    ans.d[i][j]=(ans.d[i][j]+(ll)a.d[i][k]*b.d[k][j]%mod)%mod;
        }
    }
    return ans;
}

mat add(mat a,mat b)
{
    mat ans;
    rep(i,0,num)
        rep(j,0,num)
            ans.d[i][j]=(a.d[i][j]+b.d[i][j])%mod;
    return ans;
}

mat quickmulti(mat a,int n)
{
    mat ans=E;
    while(n)
    {
        if(n&1) ans=multi(ans,a);
        a=multi(a,a);
        n>>=1;
    }
    return ans;
}

mat solve(mat a,int n)
{
    if(n<=0) return quickmulti(a,0);
    ll b=(n+1)/2;
    mat ans=solve(a,b-1);
    mat res=add(ans,multi(quickmulti(a,b),ans));
    if(n%2==0) res=add(res,quickmulti(a,n));
    return res;
}

int main()
{
    CLR(E.d);
    rep(i,0,33)
      E.d[i][i]=1;
    while(~scanf("%d",&n))
    {
        CLR(A.d);
        m.clear();
        num=0;
        REP(i,1,n)
        {
            int p1,p2;
            scanf("%d%d",&p1,&p2);
            if(!m[p1]) p1=m[p1]=++num;
            else p1=m[p1];
            if(!m[p2]) p2=m[p2]=++num;
            else p2=m[p2];
            ++A.d[p1-1][p2-1];
        }
        scanf("%d",&k);
        rep(i,0,k)
        {
            int v1,v2,t1,t2;
            scanf("%d%d%d%d",&v1,&v2,&t1,&t2);
            if(!m[v1]||!m[v2])   //这种AC的姿势必须写上这个判断,如果不写这个判断就会WA..总之数据太神了。。orzorzorzorz
            {
                printf("0\n");
                continue;
            }
            v1=m[v1]-1,v2=m[v2]-1;
            mat ans=solve(A,t1-1);
            mat ans1=solve(A,t2);
            printf("%d\n",(ans1.d[v1][v2]-ans.d[v1][v2]+mod)%mod);
        }
    }
}

神数据。。orzorzorzorz





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值