【题目描述】
求有多少个三元组(a, b, c)满足 1<=a<=b<=c<=n 且
【输入格式】
第一行一个整数 T,表示数据组数。
以下 T 行,每行两个整数 n, k。
【输出格式】
对每组数据输出单独一行“Case t: x”,t 是数据组数,x 是答案
【样例输入】
1
10 7
【样例输出】
Case 1: 27
【数据范围】
对于 30%的数据点,n <= 300
对于另外 30%的数据点,k <= 40
对于 100 的数据点,1 <= n, k <= 10^5, 1 <= T <= 400
枚举i
我们设sum[i]为余数为i的a+b^2有多少个情况
这样c就可以在sum[c^3%k]中查询
枚举b为i
a+b^2范围在[i×i+1,i×i+i]中
我们将他们%k,发现它们是很多段连续的区间
其中有i/k个完整的模数区间,即0~k-1都包括,我们不要计入sum数组了
直接在外面用一个变量cnt加上,表示0~k-1都有cnt个
接下来就是两端点了
令l=(i*i+1)%k,r=(i*i+i)%k
如果l<=r直接区间加就行了
如果l>r,那么对于(l,k-1)和(0,r)进行区间加
最后显然ans+=cnt+getsum(i*i*i%k)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long lol; 7 lol n,k; 8 lol ans,c[100001],cnt=0; 9 void add(int x,int w) 10 {int i; 11 ++x; 12 for(i=x; i<=k; i+=i&(-i)) 13 c[i]+=w; 14 } 15 int sum(int x) 16 {int i; 17 ++x; 18 int res=0; 19 for(int i=x; i; i-=i&(-i)) 20 res+=c[i]; 21 return res; 22 } 23 void update(int l,int r) 24 { 25 if (l>r) 26 { 27 add(l,1); 28 add(k,-1); 29 add(0,1); 30 add(r+1,-1); 31 } 32 else 33 { 34 add(l,1); 35 add(r+1,-1); 36 } 37 } 38 int main() 39 { 40 lol i,j,l,T,TT=0; 41 cin>>T; 42 while ((++TT)<=T) 43 { 44 scanf("%lld%lld",&n,&k); 45 memset(c,0,sizeof(c)); 46 ans=0; 47 cnt=0; 48 for (i=1; i<=n; i++) 49 { 50 cnt+=i/k; 51 if (i%k) update((i*i+1)%k,(i*i+i)%k); 52 ans+=cnt+sum(((i*i)*i)%k); 53 } 54 printf("Case %lld: %lld\n",TT,ans); 55 } 56 }