【hrbust】2298 Diamond 【数学+暴力】

题目链接: 【hrbust】2298 Diamond

枚举斜率算贡献。 n2logn 预处理, O(1) 查询。

PS:一开始写了 n2logn 每组,然后 TLE 了,思考了一下发现可以先预处理,然后每组 O(N2) ,结果又 TLE 了……然后再思考了一下发现可以 O(N) 询问,就是代码量瞬间长了一些……总体来说还是比较简单的……最后我将唯一一个 O(N) 的部分优化到了 O(1) ,即每组 O(1) 查询。

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 1005 ;

int n , m ;
int cnt[MAXN][MAXN] ;
LL sum1[MAXN][MAXN] , sum2[MAXN][MAXN] ;
int R[MAXN][MAXN] , C[MAXN][MAXN] ;
LL odd[MAXN] , even[MAXN] ; 

void solve () {
    if ( n > m ) swap ( n , m ) ;
    LL ans = 1LL * ( n * m + n + m ) * sum1[n][m] + sum2[n][m] ;
    ans -= 1LL * n * R[n][m] + 1LL * m * C[n][m] ;
    if ( n % 2 ) {
        if ( m % 2 ) ans += even[n - 1] * even[m - 1] ;
        else ans += even[n - 1] * odd[m - 1] ;
    } else {
        if ( m % 2 ) ans += odd[n - 1] * even[m - 1] ;
        else ans += odd[n - 1] * odd[m - 1] ;
    }
    ans += 1LL * n * ( n * m + n + m ) ;
    ans -= 1LL * ( n + m ) * ( 1 + n ) * n / 2 ;
    ans += 1LL * ( n - 1 ) * n * ( 2 * n - 1 ) / 6 ;
    printf ( "%lld\n" , ans ) ;
}

int main () {
    for ( int i = 1 ; i < MAXN ; ++ i ) {
        for ( int j = 1 ; j < MAXN ; ++ j ) {
            int g = __gcd ( i , j ) ;
            for ( int k = 1 ; ; ++ k ) {
                int x = k * j / g , y = k * i / g ;
                if ( x >= MAXN || y >= MAXN ) break ;
                if ( i == j && x == i ) continue ;
                if ( x % 2 == i % 2 && y % 2 == j % 2 ) {
                    cnt[max ( x , i )][max ( y , j )] ++ ;
                }
            }
        }
    }
    for ( int i = 1 ; i < MAXN ; ++ i ) {
        for ( int j = 1 ; j < MAXN ; ++ j ) {
            C[i][j] = C[i - 1][j] + cnt[i][j] * i ;
            R[i][j] = R[i][j - 1] + cnt[i][j] * j ;
            sum1[i][j] = sum1[i][j - 1] + cnt[i][j] ;
            sum2[i][j] = sum2[i][j - 1] + 1LL * cnt[i][j] * ( i - 1 ) * ( j - 1 ) ;
        }
    }
    for ( int i = 1 ; i < MAXN ; ++ i ) {
        for ( int j = 1 ; j < MAXN ; ++ j ) {
            R[i][j] += R[i - 1][j] ;
            C[i][j] += C[i][j - 1] ;
            sum1[i][j] += sum1[i - 1][j] ;
            sum2[i][j] += sum2[i - 1][j] ;
        }
    }
    for ( int i = 1 ; i < MAXN ; ++ i ) {
        odd[i] = odd[i - 1] ;
        even[i] = even[i - 1] ;
        if ( i % 2 ) odd[i] += i ;
        else even[i] += i ;
    }
    while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ;
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值