http://koistudy.net/?mid=prob_page&NO=2124
KOISTUDY
Informatica Online Judge Time Limit(Test case) : 5000(ms)Number of users who solved : 9 Total Tried : 64 The Champion of this Problem (C++) : gs16044 - ms / 1134byte My Best Submission (C++) : N/A [koistudy.net (34th 김현수)] Background 현수는 수열과 쿼리 문제 시리즈의 추
koistudy.net
기본적인 틀은 간단하다. $i$~$j$ 범위 안의 $k$ 의 개수를 구하는 것은 우선 merge sort tree 를 형성해주고
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
vector<int> tree[404040];
int n,t=1,q;
for(int i=0;i<n;i++)
{
int a; scanf("%d",&a); tree[t+i].push_back(a);
} for(int i=t-1;i>0;i--)
{
int siz1=tree[2*i].size(), siz2=tree[2*i+1].size();
for(int p=0,q=0;p<siz1||q<siz2;)
{
if(p==siz1) tree[i].push_back(tree[2*i+1][q]), q++;
else if(q==siz2) tree[i].push_back(tree[2*i][p]), p++;
else if(tree[2*i][p]<tree[2*i+1][q]) tree[i].push_back(tree[2*i][p]), p++;
else tree[i].push_back(tree[2*i+1][q]), q++;
}
}
|
cs |
upper_bound 에서 lower_bound 를 빼는 형식으로 query 를 진행해 $k$ 의 개수, 즉 $X$ 를 구해주면 된다.
1
2
3
4
5
6
7
8
9
10
|
int query(int st,int en,int num,int node,int l,int r)
{
if(r<st||en<l) return 0;
if(st<=l&&r<=en)
{
return upper_bound(tree[node].begin(),tree[node].end(),num)
-lower_bound(tree[node].begin(),tree[node].end(),num);
} int mid=(l+r)/2;
return query(st,en,num,2*node,l,mid)+query(st,en,num,2*node+1,mid+1,r);
}
|
cs |
여기서 성가신 것은 나누는 나머지가 2017이라는 것... 단순히 조합을 구하듯이 해버린다면 $k$ 가 2017 이상인 수가 들어왔을 때 $k!$ 을 2017로 나눈 나머지가 0이 되어 망해버린다.
이를 해결하기 위하여 우선 $_{X*k}C_{k}$ 가 2017의 배수인지부터 확인해주자. 2017은 다행이도 소수이므로 어떤 수에 대해서 2017의 배수의 개수, 2017*2017의 배수의 개수... 등을 확인해주면 된다. 이때 $n\leq100,000$ 이므로 $X*k$ 가 int 범위를 넘을 수 있어 long long 으로 형변환해주어야 한다. 만약 $_{X*k}C_{k}$ 가 2017의 배수라면 2017로 나눈 나머지는 0이므로 0을 출력해주자.
1
2
3
4
5
6
7
8
9
10
11
12
|
#define MOD 2017
int gesu(ll p)
{
ll ret=0;
while(p)
{
p/=MOD; ret+=p;
} return (int)ret;
}
if(gesu(1LL*X*k)-gesu(1LL*X*k-1LL*k)-gesu(1LL*k)!=0) puts("0");
|
cs |
2017로 나눈 나머지가 0이 아니라면 $_{X*k}C_{k}$ 를 실제로 2017로 나눈 값을 구해야 한다. 이때 2017의 배수가 곱해지지 않도록 하는 것이 관건이다. 이는 2016! 을 기본 단위로 하여 곱하는 것에서 해결할 수 있다. 예를 들어 $_{4040}C_{2030}$ 을 계산한다고 하자. 4040! 에서 2017이 빠진 수를 곱해야 하니 ${2016!}^2$ 를 하고 나머지 $6!$ 을 곱해주며 또한 2017 과 4034 를 지우면서 발생한 1*2 도 곱해주어야 한다. 이렇게 팩토리얼을 계산해주면 $O(NlogN)$ 이라는 시간복잡도 안에 답을 구할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
#include <bits/stdc++.h>
#define MOD 2017
using namespace std;
typedef long long ll;
vector<int> tree[404040];
int n,t=1,q,fac[7070];
int jegob(int p,ll q)
{
if(q==0) return 1;
int ret=jegob(p,q/2);
if(q%2) return ((ret*ret)%MOD)*p%MOD;
return ret*ret%MOD;
} int query(int st,int en,int num,int node,int l,int r)
{
if(r<st||en<l) return 0;
if(st<=l&&r<=en)
{
return upper_bound(tree[node].begin(),tree[node].end(),num)
-lower_bound(tree[node].begin(),tree[node].end(),num);
} int mid=(l+r)/2;
return query(st,en,num,2*node,l,mid)+query(st,en,num,2*node+1,mid+1,r);
} int gesu(ll p)
{
ll ret=0;
while(p)
{
p/=MOD; ret+=p;
} return (int)ret;
}
main()
{
scanf("%d",&n); while(t<n) t*=2;
for(int i=0;i<n;i++)
{
int a; scanf("%d",&a); tree[t+i].push_back(a);
} for(int i=t-1;i>0;i--)
{
int siz1=tree[2*i].size(), siz2=tree[2*i+1].size();
for(int p=0,q=0;p<siz1||q<siz2;)
{
if(p==siz1) tree[i].push_back(tree[2*i+1][q]), q++;
else if(q==siz2) tree[i].push_back(tree[2*i][p]), p++;
else if(tree[2*i][p]<tree[2*i+1][q]) tree[i].push_back(tree[2*i][p]), p++;
else tree[i].push_back(tree[2*i+1][q]), q++;
}
} scanf("%d",&q); fac[0]=1;
for(int i=1;i<=MOD-1;i++) fac[i]=fac[i-1]*i, fac[i]%=MOD;
while(q--)
{
int a,b,k; scanf("%d%d%d",&a,&b,&k);
int X=query(a-1,b-1,k,1,0,t-1);
if(X==0) puts("0");
else if(X==1) puts("1");
else if(gesu(1LL*X*k)-gesu(1LL*X*k-1LL*k)-gesu(1LL*k)!=0) puts("0");
else
{
int st=1,en=1;
ll imsi=1LL*X*k;
while(imsi)
{
st*=jegob(fac[MOD-1],imsi/MOD); st%=MOD;
st*=fac[imsi%MOD]; st%=MOD;
imsi/=MOD;
} imsi=1LL*k;
while(imsi)
{
en*=jegob(fac[MOD-1],imsi/MOD); en%=MOD;
en*=fac[imsi%MOD]; en%=MOD;
imsi/=MOD;
} imsi=1LL*X*k-1LL*k;
while(imsi)
{
en*=jegob(fac[MOD-1],imsi/MOD); en%=MOD;
en*=fac[imsi%MOD]; en%=MOD;
imsi/=MOD;
} st*=jegob(en,MOD-2); st%=MOD; printf("%d\n",st);
}
}
}
|
cs |
'정보과학 (Informatic) > PS' 카테고리의 다른 글
[BOJ] 16602 Brexit Negotiations (NWERC 2018) (0) | 2020.07.15 |
---|---|
[BOJ] 10075 친구 (IOI 2014) // [KOISTUDY] 1457~1459, 1461~1463 친구 1~6 (0) | 2020.06.29 |
[BOJ] 5257 timeismoney (0) | 2020.06.22 |