三元组

【题目描述】
求有多少个三元组(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 }

 

posted @ 2017-10-23 19:00  Z-Y-Y-S  阅读(5415)  评论(0编辑  收藏  举报