QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#809523#6137. Sub-cycle GraphwxqwqAC ✓177ms5380kbC++143.3kb2024-12-11 15:43:082024-12-11 15:43:09

Judging History

你现在查看的是最新测评结果

  • [2024-12-11 15:43:09]
  • 评测
  • 测评结果:AC
  • 用时:177ms
  • 内存:5380kb
  • [2024-12-11 15:43:08]
  • 提交

answer

#include <bits/stdc++.h>

using namespace std;

inline int rd()
{
	int x=0;bool f=0;char ch=getchar();
	while(ch<'0' || ch>'9') {if(ch=='-') f=1;ch=getchar();}
	while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f?-x:x;
} inline long long rdll()
{
	long long x=0;bool f=0;char ch=getchar();
	while(ch<'0' || ch>'9') {if(ch=='-') f=1;ch=getchar();}
	while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f?-x:x;
} 

#define x first
#define y second
#define vec vector
#define mp make_pair
#define pb push_back
#define upb upper_bound
#define lowb lower_bound
#define isz(x) (int)x.size()
#define gmx(a,b) (a=max(a,b))
#define gmn(a,b) (a=min(a,b))
#define fil(a,x) memset(a,x,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)

/*
// 设 f[i][k] 表示 i 个点分成 k 条链的方案数
// 那么 f[i][k]=\sum_j=2 f[i-j][k-1]*(j!/2)*C(i-1,j-1) + f[i-1][k-1]
// 记 f[n][k]
// j!*C(n-1,j-1)/2=j!*(n-1)!/(j-1)!/(n-j)!=(n-1)!*j/(n-j)!/2
// 提出 (n-1)!/2
// f[n][k]=((n-1)!/2)*\sum_j=2 f[n-j][k-1]*j/(n-j) + f[n-1][k-1]
// 发现存在相同的 g[n-j][k-1] = f[n-j][k-1]/(n-j)
// f[n][k]=((n-1)!/2)*\sum_j=2 g[n-j][k-1]*j + f[n-1][k-1]
// g[n][k]=((n-1)!/2n)*\sum_j=2^n-1 g[n-j][k-1]*j + f[n-1][k-1]/n
// 这是平方的,我们直接对着他用劲优化 k<=n
// 转移是 k-1->k
// 记 s1[i][k]=\sum j=2^i g[j][k], s2[i][k]=\sum_j=2^i-1 g[i-j][k]*j
// 那么从 s2[i][k] 开始,每次 i++ 的时候 s2[i][k]+=s1[i][k]+O(1)
// s1 怎么推,直接 +s2
看着非常复杂,实际上也非常复杂,尝试组合意义,想到了某个题
我们随一个排列,并将他分段,n!*C(n-1,m-1),对于一个方案,他被算了多少次呢
对啊这是 U438928
排列内部可以翻转,排列之间可以随意交换,那就是 2^k*k!,唯一的问题在于单点并不能贡献 2
尝试容斥,如果没有单点,那就是 n!* (插板法,相邻两个板之间 >1),这东西我们 C(n-k-1,k-1)
如果有 1 个单点,那就是枚举一个单点,剩下的是 n-1 的情况
所以是枚举有多少个单点,然后转化为这个情况

*/

typedef __int128 i128;
typedef long long LL;
typedef long double LD;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef set<int>::iterator iter;
const int N=1e5+10,MOD=1e9+7;

int qmi(int x,int k=MOD-2) {int res=1; while(k) {if(k&1) res=res*1ll*x%MOD; x=x*1ll*x%MOD,k>>=1;} return res;}

int n; LL m;
int fc[N],inv[N];
int pw2[N],inv2[N];

int C(int n,int m) {
	if(n<m) return 0;
	return fc[n]*1ll*inv[m]%MOD*inv[n-m]%MOD;
}
int calc(int n,int k) {
	return fc[n]*1ll*C(n-k-1,k-1)%MOD*inv2[k]%MOD*inv[k]%MOD;
}

signed main()
{
	int T=rd();
	fc[0]=inv[0]=1; rep(i,1,N-10) fc[i]=fc[i-1]*1ll*i%MOD;
	inv[N-10]=qmi(fc[N-10]); per(i,N-11,1) inv[i]=inv[i+1]*1ll*(i+1)%MOD;
	pw2[0]=1; rep(i,1,N-10) pw2[i]=pw2[i-1]*2%MOD;
	inv2[N-10]=qmi(pw2[N-10]); per(i,N-11,1) inv2[i]=inv2[i+1]*2ll%MOD;
	while(T--) {
		n=rd(),m=rdll();
		if(m>n) {puts("0"); continue;}
		if(m==n) {printf("%lld\n",fc[n]*1ll*qmi(2)%MOD*qmi(n)%MOD); continue;}
		if(!m) {puts("1"); continue;}
		m=n-m; int ans=0;
		rep(i,0,m) ans=(ans+calc(n-i,m-i)*1ll*C(n,i))%MOD;
		printf("%d\n",ans);
	}

	return 0;
}

详细

Test #1:

score: 100
Accepted
time: 3ms
memory: 5316kb

input:

3
4 2
4 3
5 3

output:

15
12
90

result:

ok 3 number(s): "15 12 90"

Test #2:

score: 0
Accepted
time: 177ms
memory: 5380kb

input:

17446
3 0
3 1
3 2
3 3
4 0
4 1
4 2
4 3
4 4
5 0
5 1
5 2
5 3
5 4
5 5
6 0
6 1
6 2
6 3
6 4
6 5
6 6
7 0
7 1
7 2
7 3
7 4
7 5
7 6
7 7
8 0
8 1
8 2
8 3
8 4
8 5
8 6
8 7
8 8
9 0
9 1
9 2
9 3
9 4
9 5
9 6
9 7
9 8
9 9
10 0
10 1
10 2
10 3
10 4
10 5
10 6
10 7
10 8
10 9
10 10
11 0
11 1
11 2
11 3
11 4
11 5
11 6
11 7
11...

output:

1
3
3
1
1
6
15
12
3
1
10
45
90
60
12
1
15
105
375
630
360
60
1
21
210
1155
3465
5040
2520
360
1
28
378
2940
13545
35280
45360
20160
2520
1
36
630
6552
42525
170100
393120
453600
181440
20160
1
45
990
13230
114345
643545
2286900
4762800
4989600
1814400
181440
1
55
1485
24750
273735
2047815
10239075
3...

result:

ok 17446 numbers