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