专栏文章

SP6408 KKKCT2 - Counting Triangles 2 题解

SP6408题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipspoqe
此快照首次捕获于
2025/12/03 17:19
3 个月前
此快照最后确认于
2025/12/03 17:19
3 个月前
查看原文

前置知识

等差数列求和公式

解法

考虑枚举直角顶点 (i,j),0ix,0jy(i,j),0 \le i \le x,0 \le j \le y,然后分为了 88 种贡献情况。
{a=min(i,yj)b=min(xi,j)c=min(i,j)d=min(xi,yj)\begin{cases} a=\min(i,y-j) \\ b=\min(x-i,j) \\ c=\min(i,j) \\ d=\min(x-i,y-j) \end{cases}88 种情况的贡献分别为 a,d,b,c,ad,bd,ac,ada,d,b,c,ad,bd,ac,ad,加起来后得到 (a+b+1)(c+d+1)1(a+b+1)(c+d+1)-1,但没有什么可以优化的地方。
观察乘积项,以 acac 为例,考虑固定 ii 这个常量,统计 jj 的贡献,分讨 0,yj,j,y0,y-j,j,y 划分成的三个区间内部的转移即可。

代码

CPP
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define sort stable_sort
#define endl '\n'
using namespace std;
const ll p=2009;
ll s1(ll n)
{
	return n*(n+1)/2;
}
ll s2(ll n)
{
	return n*(n+1)*(2*n+1)/6;
}
ll ask(ll up,ll a,ll b)
{
	ll ans=0;
	ans+=s1(min(a,up))+max(0ll,(up-a))*a;//2e8
	ans+=s2(min(min(a,b)-1,up));//2e12
	if(min(min(a,b)-1,up)<min(max(a,b),up))
		ans+=(min(min(a,b)-1,up)+1+min(max(a,b),up))*(min(max(a,b),up)-min(min(a,b)-1,up))/2*min(a,b);//2e12
	ans+=max(0ll,(up-max(a,b)))*a*b;//1e12
	return ans;
}
int main()
{
// #define Isaac
#ifdef Isaac
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
#endif
	int t,x,y,i,j;
	ll ans;
	cin>>t;
	for(;t>=1;t--)
	{
		cin>>x>>y;  ans=0;
		// a=min(i,y-j),b=min(x-i,j),c=min(i,j),d=min(x-i,y-j)
		for(i=0;i<=x;i++)
		{
			ans+=ask(y,i,x-i);// bc+c
			ans+=ask(y,x-i,i);// ad+d
		}
		for(i=0;i<=y;i++)
		{
			ans+=ask(x,y-i,i);// ac+a
			ans+=ask(x,i,y-i);// bd+b
		}
		cout<<ans%p<<endl;
	}	
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...