D. Excellent Arrays

题目:https://codeforces.com/contest/1550/problem/D

Let’s call an integer array a1,a2,…,an good if ai≠i for each i.

Let F(a) be the number of pairs (i,j) (1≤i<j≤n) such that ai+aj=i+j.

Let’s say that an array a1,a2,…,an is excellent if:

a is good;
l≤ai≤r for each i;
F(a) is the maximum possible among all good arrays of size n.
Given n, l and r, calculate the number of excellent arrays modulo 109+7.

Input
The first line contains a single integer t (1≤t≤1000) — the number of test cases.

The first and only line of each test case contains three integers n, l, and r (2≤n≤2⋅105; −109≤l≤1; n≤r≤109).

It’s guaranteed that the sum of n doesn’t exceed 2⋅105.

Output
For each test case, print the number of excellent arrays modulo 109+7.

Example
input
4
3 0 3
4 -3 5
42 -33 55
69 -42 146

output
4
10
143922563
698570404

Note
In the first test case, it can be proven that the maximum F(a) among all good arrays a is equal to 2. The excellent arrays are:

[2,1,2];
[0,3,2];
[2,3,2];
[3,0,1].

写个题解以后再回头看看,怎么证明的。
题目读懂了,,怎么做还是不会,看了题解证明发现真的难,没看懂为什么证明,题解代码却不难。。如果有大佬看得懂下面的证明可以评论哦,谢谢啦

题解证明:
在这里插入图片描述

代码:

#include <iostream>
using namespace std;

const int mod = int(1e9) + 7;

int norm(int a){
	
	while(a >= mod)
		a -= mod;
	while(a < 0)
		a += mod;
	return a;
}

int mul(int a,int b){ 	//求乘积 函数 
	return int(a * 1ll * b % mod);
}

int binPow(int a,int k){ //求逆元函数 
	
	int ans = 1;
	while(k > 0){
		if(k&1)
			ans = mul(ans,a);
		a = mul(a,a);
		k >>= 1;
	}
	return ans;
} 

const int N = 200*1000 + 55;

int f[N],inf[N]; //阶乘,阶乘的逆元

void precalc(){
	
	f[0] = inf[0] = 1; //0的阶乘和阶乘逆元 
	
	for(int i = 1;i<N;i++){ //费马小定理 
		
		f[i] = mul(f[i-1],i);
		inf[i] = binPow(f[i],mod-2); 
	}
} 

int C(int n,int k){ //组合数 
	
	if(k < 0 || n < k)
		return 0;
	
	return mul(f[n],mul(inf[n-k],inf[k]));	         //C(n,m) = n!/((n-m)!*m!) % (1e9+7)
}

int n,l,r;

inline void solve(){
	
	int half = n / 2;
	int st = min(1-l, r-n);
	
	int ans = mul(st,C(n,half));
	if(n & 1)
		ans = norm(ans+mul(st,C(n,half + 1)));
		
	for(int k = st+1; ;k++){
		int lf = max(1, l + k);
		int rg = min(n, r - k);
		
		if(rg + 1 - lf < 0)
			break;
		
		ans = norm(ans + C(rg + 1 - lf, half - (lf - 1)));
		if(n & 1)
			ans = norm(ans + C(rg + 1 - lf, half + 1 - (lf - 1)));
	}	
	
	cout << ans << endl;
} 

int main(){
	
	ios_base::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	
	precalc();
	
	int t; cin >> t;
	
	while(t--){
		
		cin >> n >> l >> r;
		solve();
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值