Excellent Arrays
思路:
(1)由
a
i
+
a
j
=
i
+
j
a_i+a_j=i+j
ai+aj=i+j知
a
i
a_i
ai与下标
i
i
i有关,可以令
a
i
=
i
+
k
i
a_i=i+k_i
ai=i+ki代入上式将
i
i
i和
j
j
j消掉得到
k
i
=
−
k
j
k_i=-k_j
ki=−kj的关系。为了使满足
a
i
+
a
j
=
i
+
j
a_i+a_j=i+j
ai+aj=i+j的对数尽可能的多,可以使有一部分的值都为
k
k
k,另一部分的值都为
−
k
-k
−k。易知当一半为
k
k
k一半为
−
k
-k
−k时
F
(
a
)
F(a)
F(a)的值最大。
(2)观察一下发现
k
k
k的取值不同,
a
i
a_i
ai可能只能
+
k
+k
+k或
−
k
-k
−k或都行,一开始想固定
i
i
i的位置来确定
k
k
k的范围,后来发现不太行
(3)固定
k
k
k来判断其他,如果
k
<
=
m
i
n
(
r
−
n
,
1
−
l
)
k<=min(r-n,1-l)
k<=min(r−n,1−l)每个
a
i
a_i
ai都能
+
k
+k
+k或
−
k
-k
−k否则有的只能
+
k
+k
+k或
−
k
-k
−k,遍历
k
k
k不超过
O
(
n
)
O(n)
O(n)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
const ll mod = 1e9+7;
ll f[N],inv[N];
ll qp(ll a, ll b) {
ll ret = 1;
while (b) {
if (b & 1)
ret = ret * a % mod;
a = a * a % mod;
b >>= 1;
}
return ret;
}
void init(){
f[1] = 1;
inv[1] = 1;
f[0] = 1;
inv[0] = 1;
for(int i = 2;i<N-5;i++){
f[i] = f[i-1]*i%mod;
inv[i] = inv[i-1]*qp(i,mod-2)%mod;
}
}
ll C(ll n,ll k){
if(k<0||n<k) return 0;
return f[n]*inv[n-k]%mod*inv[k]%mod;
}
int main(){
init();
ll t,n,l,r;
cin >> t;
while(t--){
cin >> n >> l >> r;
ll a = n/2,b = n-n/2;
ll ans = 0;
ll st = min(r-n,1-l);
ans += st*C(n,a)%mod;
if(n&1){
ans = (ans + st*C(n,b)%mod)%mod;
}//如果n是奇数,那么k可能有a个也可能有b个
ll L = 1,R = n;//闭区间,这个数还不确定是+k还是-k
while(1){
st++;
if(R+st>r)R--;
if(L-st<l)L++;
if((L>b+1)||(R<=a-1)) break;
ans = (ans+C(R-L+1,a-L+1))%mod;
if(n&1) ans = (ans+C(R-L+1,b-L+1))%mod;
}
cout << ans << endl;
}
return 0;
}