Problem A. Square Counting Google Kickstart Round A 2017

题意:给定一个矩形网格,问网格中有多少个正方形,包括边与网格线平行or不平行的正方形。

这题比赛时是懵逼的。。后来发现斜正方形都是平行的正方形A的内接正方形。如果A有x个点,那么共有x-1个斜正方形。画个图可以看出来。对于边和网格平行的正方形,画个图也可以看出来,如果其边长为i,那么一共有(R-i)*(C-i)个。注意这里R,C是点的个数,R-1,C-1才是边长。

正方形边长最多是x=min(R,C)-1.求和可得

ans=sum_{i=1}^x (R-i)*(C-i)*i=sum_{i=1}^x R*C*i-(R+C)*i^2+i^3

求和公式如下:

1+2+...+n=n(n+1)/2

1^2+2^2+...+n^2=n(n+1)(2n+1)/6

1^3+2^3+...+n^3=n^2(n+1)^2/4

因为最后结果要取mod,除法要预处理取逆序数+快速幂计算。

Some reminders:

1 a*b*c % mod 应该写成((a*b)%mod*c)%mod,而不是(a%mod)*(b%mod)*(c%mod),后者可能overflow

2.a-b %mod应该写成(a-b+mod)%mod,因为a和b之前都%mod,a-b可能是负数。

//
//  main.cpp
//  Practice
//
//  Created by  on 3/6/16.
//  Copyright © 2016 . All rights reserved.
//

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<ctype.h>
#include<map>
#include<time.h>
#include<set>
#include<bitset>
#include<sstream>
using namespace std;

//Kickstart Round A 2017 Problem A. Square Counting
const int maxn=60;
int T;
long long R;
long long C;
long long ans;
const int mod=1000000007;
long long inv[10];
long long pow_mod(long long a,long long b)
{
    long long s=1;
    long long t=1;
    while(b)
    {
        if(b&t)
        {
            s=(s*a)%mod;
        }
        a=(a*a)%mod;
        b=b>>1;
    }
    return s;
}
int main()
{
//    freopen("input.txt","r",stdin);
    freopen("A-large-practice.in","r",stdin);
    freopen("A.txt","w",stdout);
    scanf("%d",&T);
    for(int i=1;i<10;i++)
    {
        inv[i]=pow_mod(i,mod-2)%mod;
    }
    for(int ca=1;ca<=T;ca++)
    {
        cin>>R>>C;
        ans=0;
        long long x=min(R,C)-1;
        long long tmp0=((((R%mod*C%mod)%mod*(1+x)%mod)%mod*x)%mod*inv[2])%mod;
        long long tmp1=((((((R+C)%mod*x)%mod*(x+1))%mod)*(2*x+1))%mod*inv[6])%mod;
        long long tmp2=((((x*x)%mod*(x+1)%mod)*(x+1))%mod*inv[4])%mod;
        long long tmp=((tmp0-tmp1+mod)%mod+tmp2)%mod;//in (a-b)%mod, need to use (a-b+mod)%mod, as a may < b after mod in previous actions
        ans+=tmp;
        ans%=mod;
        printf("Case #%d: %lld\n",ca,ans);

    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值