题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6336
题目的意思就是用一个数列来产生一个无限矩阵,给出一系列询问,求所给出子矩阵的元素和。
一个比较好找的规律是M[x][y]=a[((x+y)*(x+y+1)/2+x)%L],于是一开始我把子矩阵按照斜线来求和,然后妥妥超时了……
超时代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int id(long long x,long long y,int n)
{
return ((x+y)*(x+y+1)/2+x)%n;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
int n,q,a[15];
long long sum=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
scanf("%d",&q);
while(q--)
{
long long x1,x2,y1,y2,ans=0;
scanf("%lld %lld %lld %lld",&x1,&y1,&x2,&y2);
if(x1==x2&&y1==y2)
{
int t=id(x1,y1,n);
ans=a[t];
}
else
{
long long w=x2-x1+1;
long long l=y2-y1+1;
for(int i=1;i<=l;i++)
{
if(i<=w)
{
ans+=(i/n)*sum;
int t=id(x1,y1+i-1,n);
for(int j=0;j<i%n;j++)
{
ans+=a[(t+j)%n];
}
}
else
{
ans+=(w/n)*sum;
int t=id(x1,y1+i-1,n);
for(int j=0;j<w%n;j++)
{
ans+=a[(t+j)%n];
}
}
}
//printf("%lld\n",ans);
for(int i=2;i<=w;i++)
{
if(w-i+1>=l)
{
ans+=(l/n)*sum;
int t=id(x1+i-1,y2,n);
for(int j=0;j<l%n;j++)
{
ans+=a[(t+j)%n];
}
}
else
{
ans+=((w-i+1)/n)*sum;
int t=id(x1+i-1,y2,n);
for(int j=0;j<(w-i+1)%n;j++)
{
ans+=a[(t+j)%n];
}
}
}
}
printf("%lld\n",ans);
}
}
}
TLE之后重新找规律……由样例的1 10 100构成的矩阵发现整个矩阵其实是L*L的矩阵拼成的,也就是说M[x][y]=M[x%L][y%L],然后把要求的矩阵分块,结果又WA了→_→
后来才发现原来偶数个数的数列(比如1 2)构成的矩阵是2L*2L的矩阵拼成的,两种情况合并就是M[x][y]=M[x%2L][y%2L],果然还是要多尝试几组样例呀。
AC代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
int id(long long x,long long y,int n)
{
return ((x+y)*(x+y+1)/2+x)%n;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,q,a[15],block[30][30],band[30],stripe[30];
long long sum=0;
memset(band,0,sizeof(band));
memset(stripe,0,sizeof(stripe));
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
n*=2;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
block[i][j]=a[id(i,j,n/2)];
band[i]+=block[i][j];
stripe[j]+=block[i][j];
sum+=block[i][j];
}
}
scanf("%d",&q);
while(q--)
{
long long x1,x2,y1,y2,ans=0;
scanf("%lld %lld %lld %lld",&x1,&y1,&x2,&y2);
long long w=x2-x1+1;
long long l=y2-y1+1;
ans=sum*(w/n)*(l/n);
int tmp=x1%n,temp=y1%n;
for(int i=0;i<w%n;i++)
{
ans+=band[(tmp+i)%n]*(l/n);
}
for(int i=0;i<l%n;i++)
{
ans+=stripe[(temp+i)%n]*(w/n);
}
for(int i=0;i<w%n;i++)
{
for(int j=0;j<l%n;j++)
{
ans+=block[(i+x1)%n][(j+y1)%n];
}
}
printf("%lld\n",ans);
}
}
}