QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#809523 | #6137. Sub-cycle Graph | wxqwq | AC ✓ | 177ms | 5380kb | C++14 | 3.3kb | 2024-12-11 15:43:08 | 2024-12-11 15:43:09 |
Judging History
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