L i n k Link Link
l u o g u P 2119 luogu\ P2119 luogu P2119
D e s c r i p t i o n Description Description
S a m p l e Sample Sample I n p u t Input Input 1 1 1
30 8
1
24
7
28
5
29
26
24
S a m p l e Sample Sample O u t p u t Output Output 1 1 1
4 0 0 0
0 0 1 0
0 2 0 0
0 0 1 1
1 3 0 0
0 0 0 2
0 0 2 2
0 0 1 0
S a m p l e Sample Sample I n p u t Input Input 2 2 2
15 15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
S a m p l e Sample Sample O u t p u t Output Output 2 2 2
5 0 0 0
4 0 0 0
3 5 0 0
2 4 0 0
1 3 0 0
0 2 0 0
0 1 0 0
0 0 0 0
0 0 0 0
0 0 1 0
0 0 2 1
0 0 3 2
0 0 4 3
0 0 5 4
0 0 0 5
H i n t Hint Hint
T r a i n Train Train o f of of T h o u g h t Thought Thought
设一个
t
=
x
d
−
x
c
t = x_d - x_c
t=xd−xc
然后三个约束条件魔改一下就变成了
6
t
<
x
c
−
x
b
6t<xc−xb
6t<xc−xb
把差补上,就变成了
6
t
+
k
=
x
c
−
x
b
6t+k=xc−xb
6t+k=xc−xb
A,B,C的关系就知道了
然后枚举t,分别再枚举A和D求前缀和 和 后缀和
具体看代码吧
C o d e Code Code
#include<iostream>
#include<cstdio>
using namespace std;
int n, m, sum;
int x[40005], vis[20005];
int a[40005], b[40005], c[40005], d[40005];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i)
{
scanf("%d", &x[i]);
vis[x[i]]++;
}
for (int t = 1; t * 9 < n; ++t)
{
int sum = 0;
for (int D = 9 * t + 2; D <= n; ++D)
{
int A = D - 9 * t - 1;
int B = A + 2 * t;
int C = D - t;
sum += vis[A] * vis[B];//求出A与B的组合情况
c[C] += sum * vis[D];//确定A之后再看D点就可以得到C点的情况
d[D] += sum * vis[C];
}
sum = 0;
for (int A = n - t * 9 - 1; A; --A)
{
int B = A + 2 * t;
int C = B + 6 * t + 1;
int D = A + 9 * t + 1;
sum += vis[C] * vis[D];//先确定CD两点
a[A] += sum * vis[B];
b[B] += sum * vis[A];
}
}
for (int i = 1; i <= m; ++i)
printf("%d %d %d %d\n", a[x[i]], b[x[i]], c[x[i]], d[x[i]]);
}
我是看了↓这个带佬的blog才懂得,如果这篇blog没看的很懂可以再看看这篇
传送门