传送门
文章目录
- 题意:
- 思路:
题意:
给你一个数组aia_iai,定义一个数组是好的当且仅当对于所有iii都有ai!=ia_i!=iai!=i。定义f(a)f(a)f(a)表示数组aaa中i<j,ai+aj=i+ji<j,a_i+a_j=i+ji<j,ai+aj=i+j的(i,j)(i,j)(i,j)对数。定义一个数组是极好的包含以下三个条件:
(1)a(1)a(1)a数组是好的。
(2)l≤ai≤r(2)l\le a_i\le r(2)l≤ai≤r
(3)f(a)(3)f(a)(3)f(a)在所有的好的数组中是最大的。
给定l,rl,rl,r,让你求出来有多少个极好的数组。
n≤2e5,−109≤l≤1,n≤r≤109n\le2e5,-10^9\le l\le1,n\le r\le 10^9n≤2e5,−109≤l≤1,n≤r≤109
思路:
首先考虑f(a)f(a)f(a)最大的时候是什么情况,如果没有ai!=ia_i!=iai!=i的条件,肯定是ai=ia_i=iai=i的时候最大。现在有这个条件,那么我们可以将其加上一个偏移量kkk,即ai+k,ai−ka_i+k,a_i-kai+k,ai−k,考虑长度nnn的数组,一定是一半ai+ka_i+kai+k,另一半ai−ka_i-kai−k,这样f(a)=⌈n2⌉∗⌊n2⌋f(a)=\left \lceil \frac{n}{2} \right \rceil * \left \lfloor \frac{n}{2} \right \rfloorf(a)=⌈2n⌉∗⌊2n⌋,此时一定是最大的。
通过以上分析,我们知道每个位置一定是加上或减去一个偏移量kkk构造出来的数组才有可能是极好的数组,由于aia_iai的范围有限制,我们分以下几种情况讨论:
(1)k≤min(1−l,r−n)(1)k\le min(1-l,r-n)(1)k≤min(1−l,r−n)
此时对于每个位置ai+k,ai−ka_i+k,a_i-kai+k,ai−k两个数都不会超过范围,所以当nnn为偶数的时候,可以选择n/2n/2n/2个位置+k+k+k,贡献就是C(n,n/2)C(n,n/2)C(n,n/2),是奇数的时候,可以选择n/2n/2n/2个位置+k+k+k或者n/2+1n/2+1n/2+1个位置+k+k+k。
(2)k>min(1−l,r−n)(2)k>min(1-l,r-n)(2)k>min(1−l,r−n)
我们设k=min(1−l,r−n)+1k=min(1-l,r-n)+1k=min(1−l,r−n)+1,那么有max(1,l+k)−1max(1,l+k)-1max(1,l+k)−1个人必须+k+k+k,有n−min(n,r−k)n-min(n,r-k)n−min(n,r−k)个人必须−k-k−k,否则他们就越界了。设减去上述两个剩下的位置是restrestrest,那么问题转换成跟第一种情况一样了,只是从nnn变成了restrestrest。
注意第二种情况我们不需要特判,只需要在求C(n,m)C(n,m)C(n,m)的时候判断一下n,m<0,n<mn,m<0,n<mn,m<0,n<m的情况直接返回000即可。
第二种情况最多迭代nnn次,复杂度O(n)O(n)O(n)。
// Problem: D. Excellent Arrays
// Contest: Codeforces - Educational Codeforces Round 111 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1550/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;int n,l,r;
LL fun[N],inv[N];LL qmi(LL a,LL b) {LL ans=1; a%=mod;while(b) {if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans%mod;
}LL C(int a,int b) {if(a<0||b<0||a<b) return 0;return fun[a]*inv[b]%mod*inv[a-b]%mod;
}int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);fun[0]=1;for(int i=1;i<N;i++) fun[i]=fun[i-1]*i%mod;inv[N-1]=qmi(fun[N-1],mod-2);for(int i=N-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;int _; scanf("%d",&_);while(_--) {scanf("%d%d%d",&n,&l,&r);int begin=min(1-l,r-n);LL ans=0;if(n%2==0) ans+=C(n,n/2)*begin%mod;else ans+=(C(n,n/2)+C(n,n/2+1))%mod*begin%mod;for(LL t=begin+1,cnt=n;cnt;t++,cnt--) {int lcnt=max(1ll,l+t)-1;int rcnt=n-min(1ll*n,r-t);int rest=n-lcnt-rcnt;if(n%2==0) ans+=C(rest,n/2-lcnt),ans%=mod;else ans+=(C(rest,n/2-rcnt)+C(rest,n/2-rcnt+1))%mod,ans%=mod;}printf("%lld\n",ans%mod);}int c;return 0;
}
/**/