(1)题目大意
给定你两个数n,m,在m个数中选择n个数组成A序列,从m中选择n个数再组成一个B序列。
现在问你满足Ai ≠ Bi的并且Ai ≠ Aj的序列总数有多少?
(2)解题思路
我们先把一个序列固定,对于另一个序列,我们可以利用容斥原理容易解的,对于我们有0个相同的是我们刚开始必然的答案数,若是有1个相同的那么我们就需要减去,但是我们就会减去多的有两个相同的方案,因此我们需要加上有两个相同的方案,因此奇数减偶数加。最后我们的第一个序列的总数是C(m,n),因此答案就出来了。
(3)代码实现
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
const int N = 1010000,mod = 1e9 + 7;
ll fac[N],inv[N];
ll C(int a,int b)
{
if(a < b) return 0;
return fac[a] * inv[b] % mod * inv[a - b] % mod;
}
ll P(int a,int b)
{
if(a < b) return 0;
return fac[a] * inv[a - b] % mod;;
}
void exgcd(int a,int b,ll &x,ll &y)
{
if(!b) {
x = 1,y = 0;
return ;
}
exgcd(b,a % b,y,x);
y -= a / b * x;
}
void init(int n)
{
ll x,y;
fac[0] = inv[0] = 1;
for(int i = 1;i <= n;i++) fac[i] = i * fac[i - 1] % mod;
exgcd(fac[n],mod,inv[n],y);
inv[n] = (inv[n] % mod + mod) % mod;
for(int i = n - 1;i >= 1;i--) inv[i] = inv[i + 1] * (i + 1) % mod;
}
int main()
{
init(1e6);
int n,m;
cin >> n >> m;
ll ans = 0,p = 1;
for(int i = 0;i <= n;i++) {
ans = (ans + p * C(n,i) * P(m - i,n - i) % mod) % mod;
p = -p;
}
cout << P(m,n) * ((ans + mod) % mod) % mod << endl;
return 0;
}
(1)题目大意
给定的是一个字符串S,有多少不同的字符串可以作为一个非空的,不一定是连续的S子序列的排列?因为计数可能非常大,所以按998244353进行模数打印。
(2)解题思路
这个题考虑进行组合数预处理,然后进行dp,dp[i][j],表示有i类字符,选j个的方案数。
那么我们把这个字符串的每个字符进行预处理,然后从0-25,依次处理。
状态转移就是:dp[i + 1][j + k] = (dp[i + 1][j + k] + dp[i][j] * C[j + k][k] % mod) % mod
从i+1类字符中选j+k个可以从第i类字符中选j个*从j+k中选k个的方案数,j是前面字符的个数。
(3)代码实现
#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 5e3 + 10;
const int mod = 998244353;
ll dp[30][N], C[N][N];
int cnt[N];
void init()
{
C[0][0] = 1;
for (int i = 1; i <= 5000; i++)
{
C[i][0] = 1;
for (int j = 1; j <= i; j++)
{
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
}
}
}
void solve()
{
string s;
cin >> s;
for (int i = 0; i < s.size(); i++)
{
cnt[s[i] - 'a']++;
}
dp[0][0] = 1;
ll ans = 0, sum = 0;
for (int i = 0; i < 26; i++)
{
for (int j = 0; j <= sum; j++)
{
for (int k = 0; k <= cnt[i]; k++)
{
dp[i + 1][j + k] = (dp[i + 1][j + k] + dp[i][j] * C[j + k][k] % mod) % mod;
}
}
sum += cnt[i];
sum %= mod;
}
for (int i = 1; i <= s.size(); i++)
{
ans = (ans + dp[26][i]) % mod;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
init();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}
(1)题目大意
给定N个整数序列:a = (A1, A2,…一个)。找出(不一定是连续的)子序列A' = (A1', A2',…), Ak')长度至少2,满足以下条件:A1' <= Ak'由于计数可能非常大,按998244353的模量打印。在这里,当两个子序列来自不同的索引集时,即使它们与序列相同,也要区分它们。
(2)解题思路
对于第i个数,我们查询前面所有比他小的都能构成方案,然后这两个数中间的数随便选,显然是个二项式系数,最后方案为2^len,但是我们不容易维护出这个前面比他小的数量能够O1算答案,因此我们考虑离散化A数组,对于每一个位置我们都插入树状数组2的i次方的逆元,然后我们查询前面有多少比他小的就会把这些逆元加上来,然后*2^i次方,然后除以2即可。
(3)代码实现
// Problem: E - LEQ
// Contest: AtCoder - AtCoder Beginner Contest 221
// URL: https://atcoder.jp/contests/abc221/tasks/abc221_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include "bits/stdc++.h"
#define rep(i, z, n) for (ll i = z; i <= n; i++)
#define per(i, n, z) for (ll i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<ll, ll>
#define fi first
#define se second
#define vi vector<ll>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const ll mod = 998244353;
const ll N = 3e5 + 10;
ll pw[N], inv[N], a[N], seg[N], m;
ll ksm(ll a, ll p)
{
ll res = 1;
while (p)
{
if (p & 1)
res = 1LL * res * a % mod;
a = 1LL * a * a % mod;
p >>= 1;
}
return res;
}
ll lowbit(ll x)
{
return x & -x;
}
void add(ll x, ll v)
{
while (x <= m)
{
seg[x] = (seg[x] + v) % mod;
x += lowbit(x);
}
}
ll qry(ll x)
{
ll res = 0;
while (x >= 1)
{
res = (res + seg[x]) % mod;
x -= lowbit(x);
}
return res;
}
void init()
{
ll n = 3e5;
pw[0] = inv[0] = 1;
for (ll i = 1; i <= n; i++)
{
pw[i] = pw[i - 1] * 2 % mod;
}
inv[n] = ksm(pw[n], mod - 2);
for (ll i = n - 1; i >= 1; i--)
{
inv[i] = 2 * inv[i + 1] % mod;
}
}
vector<ll> v;
void solve()
{
ll n;
cin >> n;
for (ll i = 1; i <= n; i++)
{
cin >> a[i];
v.push_back(a[i]);
}
sort(v.begin(), v.end());
m = v.size();
ll ans = 0;
for (ll i = 1; i <= n; i++)
{
ll idx = lower_bound(v.begin(), v.end(), a[i]) - v.begin();
ans = (ans + 1LL * qry(idx + 1) * pw[i] % mod * inv[1] % mod) % mod;
add(idx + 1, inv[i]);
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
init();
ll T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}