Problem E. Matrix from Arrays HDU - 6336 (容斥,打表找规律)

Problem E. Matrix from Arrays

 题目链接:HDU - 6336 

题意:按照题目方法构造一个矩阵,给出左上角和右下角的坐标问以两点连线为对角线的矩阵的和;

思路:打表发现,当L是奇数时,构造的矩阵是一个L*L的循环矩阵;L是偶数时,构造的矩阵是一个2L*2L的循环矩阵;那么统一把循环节设为2L即可;先打表构造出循环矩阵,求前缀和sum[i][j];最好让矩阵的x, y都从1开始;将题目给出的稍微修改一下就可以了;

 

          

                     (图一)                                                   (图二)

             (图三)     

如图一:以3*3的循环矩阵为例,紫色矩阵是目标矩阵,可以转化成图二,根据容斥原理S=S1-S2-S3+S4;;S1, S2, S3, S4都是以(x, y)为右下角,以(0, 0)为左上角的矩阵,问题就转化成了求这样的矩阵图三;米黄色的面积表示有多少个完整的循环矩阵,下方白条及右方白条表示只有长或宽不完整的矩阵,橙黄色面积表示不完整的循环矩阵;

 

注意要用long long;

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll len, M[110][110], sum[25][25], a[20];
ll Sum(ll x, ll y){
	ll ans=(x/len)*(y/len)*sum[len][len];//求米黄色部分和;
	ans+=sum[x%len][len]*(y/len)+sum[len][y%len]*(x/len);//求白条部分和
	ans+=sum[x%len][y%len];//求橙黄色部分和;
	return ans;
}
int main(){
	int T;
	scanf("%d", &T);
	while(T--){
		ll L;
		scanf("%lld", &L);
		for(ll i=0; i<L; i++){
			scanf("%lld", &a[i]);
		}
		ll cnt=0;
		for(ll i=0; i<=100; i++){
			for(ll j=0; j<=i; j++){
				M[j+1][i-j+1]=a[cnt];
				cnt=(cnt+1)%L;
			}
		}
		len=2*L;
		memset(sum, 0, sizeof(sum));
		for(ll i=1LL; i<=len; i++){
			for(ll j=1LL; j<=len; j++){
				sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+M[i][j];
			}
		}
		int Q;
		scanf("%d", &Q);
		while(Q--){
			ll x0, x1, y0, y1;
			scanf("%lld%lld%lld%lld", &x0, &y0, &x1, &y1);
			x0++, x1++, y0++, y1++;
			ll ans=Sum(x1, y1)-Sum(x1, y0-1)-Sum(x0-1, y1)+Sum(x0-1, y0-1);//S=S1-S2-S3+S4;
			printf("%lld\n", ans);
		}
	}
	return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值