题目大意:
是一个圆上有n个点,我们有m种颜色,去给这些点染色。
能构成三角形的点不能是同一种颜色。
思路:
我们应该知道圆的直径和圆上其余任意一点都能构成三角形。
如何处理这个染色其实蛮复杂的。不过做法就是正面去做去分析。
——
首先我们可以统计出有多少对直径,这里设为 c 对。(用set统计,本人一开始暴力超时了,,)
——
我们分析可知,三角形有两种情况:
1,直径的两点不同,第三点随意。
2,直径两点相同,第三点必须与之不同。(这种情况要求各直径颜色都不同,因为互相构成三角形。所以需要占据某种颜色)
——分类
所以我们先划分直径点对。
c对中有 i 对时相同的,剩下c-i 对就是不同的。
(这里 i 可以小,不一定可以大,因为要占据颜色a种。我们最后再分析。)
剩下c - i 对,每对不同即可,互相不干扰。
以及剩下 n - c*2 个单独的点,他们在 m - i 种颜色中自由选择。
——式子
(C是组合函数,C(c,i)指c对里面选i个,a是阶乘,见板子排列组合板子 A C-CSDN博客)
所以直径颜色相同 i 对时总数为:
C
(
c
,
i
)
∗
C
(
m
,
i
)
∗
a
[
i
]
∗
(
m
−
i
)
c
−
i
∗
(
m
−
i
−
1
)
c
−
i
∗
(
m
−
i
)
n
−
c
∗
2
C(c,i ) * C(m, i ) * a[ i ] * (m - i)^{c-i} *(m-i-1)^{c-i}*(m-i)^{n-c*2}
C(c,i)∗C(m,i)∗a[i]∗(m−i)c−i∗(m−i−1)c−i∗(m−i)n−c∗2
——i的取值
i 的上限应为 min( m , c )
此处有异议,因为当我们 c 大于 m 时,我们可以有 i == m - 1 对颜色相同,剩下只有 1 种颜色了,而我们剩下的 c - (m-1) 对需要颜色不同,至少也得两种颜色啊。
其实我们看式子,当 i 为 m - 1 时,有一项 m - i - 1 就为0了,那么整个式子就是0了,所以这种情况不会影响我们的答案。
这种情况也是不会出现的。
所以 i == m 时,剩下的没颜色选了,也是+0种,不影响答案。
所以 i <= min( m , c )
(取c的话颜色就充足了嘛,冲突的不会计入的)
参考代码:
#define ll long long
#define endl "\n"
#define int long long
const ll inf = 1e9;
const ll MOD = 998244353;
int a[300005];
ll ksm(int x, int y, int mod)
{
if (x == 1) return 1;
ll res = 1, base = x;
while (y) {
if (y & 1) res = (res * base) % mod;
base = (base * base) % mod;
y >>= 1;
}
return res;
}
ll C(ll n, ll m, ll p)
{
if (m > n)return 0;
return ((a[n] * ksm(a[m], p - 2, p)) % p * ksm(a[n - m], p - 2, p) % p);
}
ll A(ll n, ll m, ll p)
{
if (m > n)return 0;
return (a[n] * ksm(a[n - m], p - 2, p)) % p;
}
//距离为周长一半即是半径
void solve()
{
int n, m;
cin >> n >> m;
int sum = 0;
vector<int>arr(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> arr[i];
sum += arr[i];
}
if (sum % 2 == 0)
{
int couple = 0;
//vector<int>vis(n + 1);
set<int>vis;
int cur = 0;
for (int i = 1; i <= n; i++)
{
cur += arr[i];
if (vis.count(cur))
{
couple++;
}
vis.insert(cur + sum / 2);
}
int c = n - couple * 2;
int ans = 0;
for (int i = 0; i <= min(couple,m)/* && i <= m - 2||i==couple&&m-i>=1||n==couple*2&&m>=couple+2&&i<=couple*/; i++)
{
ans = (ans + C(couple, i, MOD) * a[i] % MOD * C(m, i, MOD) % MOD
//选出a对,m中选出a种颜色,a的阶乘种
* ksm(m-i,couple-i,MOD) % MOD * ksm(m-i-1,couple-i,MOD) % MOD
* ksm(m - i, n - couple * 2, MOD) % MOD) % MOD;
}
cout << ans;
}
else//没有直径
{
cout << ksm(m, n, MOD) % MOD;
}
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
a[0] = a[1] = 1;
for (int i = 2; i <= 300000; i++)
{
a[i] = a[i - 1] * i % MOD;
}
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}