题目链接:
http://codeforces.com/problemset/problem/57/C
题意:
给你一个数n,表示有n个数的序列,每个数范围为[1,n],叫你求所有非降和非升序列的个数。
题解:
由于对称性,我们只要求非降序的个数就可以了(n个数全部相等的情况既属于非升也属于非降)
我们在满足条件的n个数之前加一个虚节点1,在第n个数之后加一个n,那么考虑这n+2个数组成的非降序列:
假设序列里的第i个数为a[i],我们设xi=a[i+1]-a[i]+1,1<=i<=n+1,则满足每个数>=1,且sum(x[1],x[2]...x[n+1])=2*n;
那么相当于求将2*n分成n个部分,且每个部分的值大于等于1,则易得非降序列总数为:C(n,2*n-1)(2*n-1 选 n)
所以最后的答案是2*C(n,2*n-1)-n;
代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 6 const int mod = 1000000007; 7 typedef long long LL; 8 int n; 9 //扩展欧几里得 10 void gcd(int a, int b, int &d, int &x, int &y) { 11 if (!b) { d = a; x = 1; y = 0; } 12 else { gcd(b, a%b, d, y, x); y -= x*(a / b); } 13 } 14 //求逆元 15 int inv(int a) { 16 int d, x, y; 17 gcd(a, mod, d, x, y); 18 return x; 19 } 20 //求阶乘 21 int solve(int _n,int x) { 22 LL ret = 1; 23 while (_n--) { 24 ret *= x; 25 ret %= mod; 26 x--; 27 } 28 return ret; 29 } 30 31 int main() { 32 while (scanf("%d", &n) == 1 && n) { 33 int ans = (LL)solve(n, 2 * n - 1)*inv(solve(n,n))%mod; 34 ans = ans * 2 - n; 35 ans = (ans%mod + mod) % mod; 36 printf("%d\n", ans); 37 } 38 return 0; 39 }
时间: 2024-10-06 00:41:26