2013 Multi-University Training Contest 9

1001 Arc of Dream

简单的构造矩阵,矩阵乘加快速幂解决。还可以推公式。

矩阵法:

5X5矩阵  1 0 0 0 0

 1 ax*bx 0 0 0

 0 ax*by ax 0 0

   0 ay*bx 0 bx 0

 0 ay*by ay by 1

构造这样一个矩阵,然后用矩阵乘和矩阵快速幂得到一个新矩阵。

sum=(ai%N*bi%N*ty[1][0]%N+ai%N*ty[2][0]%N+bi%N*ty[3][0]%N+ty[4][0]%N)%N;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<vector>
#define mem(a,b) memset(a,b,sizeof(a))
#define FOR(a,b,i) for(i=a;i<=b;++i)
#define For(a,b,i) for(i=a;i<b;++i)
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
__int64 tx[5][5],ty[5][5],tz[5][5];
void mat(__int64 a[5][5],__int64 b[5][5])//矩阵乘
{
    __int64 d[5][5];
    int i,j,l;
    mem(d,0);
    For(0,5,i)
    {
        For(0,5,j)
        {
            For(0,5,l)
            {
                d[i][j]=(d[i][j]+a[i][l]*b[l][j]%N)%N;
            }
        }
    }
    For(0,5,i)
    {
        For(0,5,j)
        {
            a[i][j]=d[i][j];
        }
    }
}
void g(__int64 x)//矩阵快速幂,用的都是自己用的模板
{
    mem(ty,0);
    __int64 ans;
    int i,j;
    For(0,5,i)
    {
        For(0,5,j)
        {
            tz[i][j]=tx[i][j];
        }
    }
    For(0,5,i)
    {
        ty[i][i]=1;
    }
    while(x>0)
    {
        if(x%2==1)
        {
            mat(ty,tz);
        }
        mat(tz,tz);
        x/=2;
    }
}
int main()
{
    __int64 n,ai,ax,ay,bi,bx,by,sum;
    while(scanf("%I64d%I64d%I64d%I64d%I64d%I64d%I64d",&n,&ai,&ax,&ay,&bi,&bx,&by)!=EOF)
    {
        mem(tx,0);
        tx[0][0]=tx[1][0]=tx[4][4]=1;//构造矩阵
        tx[1][1]=ax*bx%N;
        tx[2][1]=ax*by%N;
        tx[3][1]=ay*bx%N;
        tx[4][1]=ay*by%N;
        tx[2][2]=ax%N;
        tx[3][3]=bx%N;
        tx[4][2]=ay%N;
        tx[4][3]=by%N;
        g(n);
        sum=(ai%N*bi%N*ty[1][0]%N+ai%N*ty[2][0]%N+bi%N*ty[3][0]%N+ty[4][0]%N)%N;//求和
        printf("%I64d\n",sum);
    }
    return 0;
}
公式法:

首先考虑一些特殊情况:当ax和bx都为1时,则两式为等差数列相乘,而当其中一个为1时,可以通过递推,找到其中是由等比数列和等差数列相乘的部分,这样的话可以分别处理,包括等比数列的求和公式,错位相减法等。而两个都不为1时的情况,就是上面情况的一般化,也可以相应的递推。这题中n为一个很大的数,而且需要取1000000007的模,所以在运用到除法时,就得需要求逆元。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<vector>
#define mem(a,b) memset(a,b,sizeof(a))
#define FOR(a,b,i) for(i=a;i<=b;++i)
#define For(a,b,i) for(i=a;i<b;++i)
#define N 1000000007
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
__int64 pw(__int64 x,__int64 y)//快速幂取模
{
    __int64 res=1;
    x=x%N;
    while(y>0)
    {
        if(y%2==1)
        {
            res=(res*x)%N;
        }
        x=(x*x)%N;
        y/=2;
    }
    return res%N;
}
__int64 f(__int64 x,__int64 y)//求逆元
{
    x=x%N;
    return (x*pw(y,N-2))%N;
}
int main()
{
    __int64 n,ai,ax,ay,bi,bx,by,r1,r2,sum,s1,s2,s3;
    while(scanf("%I64d%I64d%I64d%I64d%I64d%I64d%I64d",&n,&ai,&ax,&ay,&bi,&bx,&by)!=EOF)
    {
        if(n==0)
        {
            printf("0\n");
        }
        else
        {
            sum=0;
            r1=f((n%N)*((n-1)%N)%N,2);//这是1-(n-1)数的和
            r2=f(((n-1)%N)*(n%N)%N*((n%N*2-1)%N)%N,6);//这是1^2-(n-1)^2数的和
            if(ax==1&&bx==1)
            {
                sum=(sum+n%N*ai%N*bi%N+r2*(by*ay%N)%N+(r1*((by*ai%N+bi*ay%N)%N))%N)%N;
            }
            else if(bx==1)//这和下面一种情况是一样的
            {
                sum=(sum+f(n%N*ay%N*bi%N,1-ax)+f(r1*by%N*ay%N,1-ax)+f((1-pw(ax,n))*(ai*bi%N*(1-ax)%N-ay*bi%N)%N,(1-ax)*(1-ax))+f((f(ax-pw(ax,n),(1-ax)*(1-ax))-f((n-1)%N*pw(ax,n)%N,1-ax))*(by*ai%N*(1-ax)%N-ay*by%N),1-ax))%N;
            }
            else if(ax==1)
            {
                swap(ax,bx);
                swap(ay,by);
                swap(ai,bi);
                sum=(sum+f(n%N*ay%N*bi%N,1-ax)+f(r1*by%N*ay%N,1-ax)+f((1-pw(ax,n))*(ai*bi%N*(1-ax)%N-ay*bi%N)%N,(1-ax)*(1-ax))+f((f(ax-pw(ax,n),(1-ax)*(1-ax))-f((n-1)%N*pw(ax,n)%N,1-ax))*(by*ai%N*(1-ax)%N-ay*by%N),1-ax))%N;
            }
            else
            {
                s1=f(1-pw(ax*bx%N,n),1-ax*bx);
                s2=f(1-pw(bx,n),1-bx);
                s3=f(1-pw(ax,n),1-ax);
                sum=(sum+f(by*ay%N,(1-ax)*(1-bx))*(n%N)%N+f(s1*(ay*by%N-ay*bi%N*(1-bx)%N-by*ai%N*(1-ax)%N+ai*bi%N*(1-ax)%N*(1-bx)%N)%N,(1-ax)*(1-bx))%N+f(s2*(ay*bi%N*(1-bx)%N-ay*by%N)%N,(1-ax)*(1-bx))%N+f(s3*(by*ai%N*(1-ax)%N-ay*by%N)%N,(1-ax)*(1-bx))%N)%N;
            }
            sum=(sum+N)%N;
            printf("%I64d\n",sum);
        }
    }
    return 0;
}

这公式题写得我都凌乱了。。。

1005 EBCDIC

码农题,200多的对应,只要打表就行,就不写了。


1006 Front compression

这题应该是个后缀数组,但我是直接暴力做得,目测数据水了,但题意是不是写得太不清楚了一点,我是赛后看的题,还是没觉得它有说是后一个只要与前一个比较就行。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a))
#define FOR(a,b,i) for(i=a;i<=b;++i)
#define For(a,b,i) for(i=a;i<b;++i)
using namespace std;
inline void RD(int &ret)
{
    char c;
    do
    {
        c=getchar();
    }
    while(c<'0'||c>'9');
    ret=c-'0';
    while((c=getchar())>='0'&&c<='9')
    {
        ret=ret*10+(c-'0');
    }
}
inline void OT(int a)
{
    if(a>=10)
    {
        OT(a/10);
    }
    putchar(a%10+'0');
}
char s[100001];
int main()
{
    int i,j,a,b,m,n,p,q,s1,s2;
    __int64 x,y;
    while(scanf("%s",s)!=EOF)
    {
        RD(n);
        x=y=0;
        m=n;
        m--;
        p=q=100005;
        while(n--)
        {
            RD(a);
            RD(b);
            if(n!=m)
            {
                if(a==p)
                {
                    s1=min(b,q)-p;
                }
                else
                {
                    j=0;
                    while((a+j)<b&&(p+j)<q&&s[a+j]==s[p+j])
                    {
                        j++;
                    }
                    s1=j;
                }
            }
            else
            {
                s1=0;
            }
            if(s1==0)
            {
                s2=1;
            }
            else
            {
                j=s1;
                i=0;
                while(j>0)
                {
                    j/=10;
                    i++;
                }
                s2=i;
            }
            x+=b-a+1;
            y+=b-a+s2-s1+2;
            p=a;
            q=b;
        }
        printf("%I64d %I64d\n",x,y);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值