牛客小白月赛73
A 最小的数字
#include <bits/stdc++.h>
using namespace std;
#define int long long
int32_t main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int n;
cin >> n;
cout << ((n+2ll)/3ll)*3ll << "\n";
return 0;
}
B 优美的GCD
#include <bits/stdc++.h>
using namespace std;
#define int long long
int32_t main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while( t -- ){
int n ;
cin >> n;
cout << n << " " << n*2 << "\n";
}
return 0;
}
C 优美的序列
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin >> n;
vector<int> a(n);
for( auto &i : a ) cin >> i;
sort( a.begin(), a.end() );
for( int i = 1 ; i < n ; i ++ ){
if( a[i] == a[i-1] ){
cout << "-1\n";
return ;
}
}
for( auto i : a )
cout << i << " ";
cout << "\n";
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while( t -- )
solve();
return 0;
}
DE Kevin喜欢零
没有写简单版本。
首先知道的是,末尾的\(0\),一定是区间内\(2,5\)的数量决定的,如果可以计算出\(2,5\)的数量的最小值,就可以知道答案。
我们可以用前缀和维护\(2,5\)的数量,因为前缀和的单调性,所以可以枚举左端点并二分出右端点的取值范围。
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n , k;
cin >> n >> k;
vector<int> a(n+1) , b(n+1);
for( int i = 1 , x ; i <= n ; i ++ ){
cin >> x;
while( x % 2 == 0 ) x /= 2 , a[i] ++;
while( x % 5 == 0 ) x /= 5 , b[i] ++;
}
for( int i = 1 ; i <= n ; i ++ )
a[i] += a[i-1] , b[i] += b[i-1];
auto f = [a,b]( int l , int r ){
return min( a[r] - a[l-1] , b[r] - b[l-1] );
};
int res = 0;
for( int i = 1 , x , y , l , r , mid ; i <= n ; i ++ ) {
l = i, r = n, x = -1;
while (l <= r) {
mid = (l + r) >> 1;
if (f(i, mid) >= k) x = mid, r = mid - 1;
else l = mid + 1;
}
l = i, r = n, y = -1;
while (l <= r) {
mid = (l + r) >> 1;
if (f(i, mid) <= k) y = mid, l = mid + 1;
else r = mid - 1;
}
if (x == -1 || y == -1) continue;
if (f(i, x) != k || f(i, y) != k ) continue;
res += max( 0ll, y - x + 1);
}
cout << res << "\n";
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t;
cin >> t;
while( t -- ) solve();
return 0;
}
F Kevin的哈希构造
比较经典的 dp 思路吧。
\(f[i][j][x]\)表示前\(i\)位恰好\(j\)位相同且哈希值为\(x\)的方案是否存在。我们枚举状态后,在枚举出当前位选的字母\(c\),则状态转移方程为\(f[i+1][j+(c=s_i)][(x\times b + c ) \mod p] |= f[i][j][x]\)
我们再维护前缀状态就可以还原出一个合法的串。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define V vector
#define ll long long
#define mp make_pair
int hashMod(string s, int b, int p) {
int ans = 0;
for (auto c: s)
ans = (ans * b + c - 'a' + 1) % p;
return ans;
}
int power(int x, int y, int p) {
int ans = 1;
while (y) {
if (y & 1) ans = ans * x % p;
x = x * x % p, y >>= 1;
}
return ans;
}
void solve() {
int n, base, mod, k;
string s;
cin >> n >> base >> mod >> k >> s;
V<V<V<bool>>> f(n + 1, V<V<bool>>(k + 2, V<bool>(mod + 1, 0)));
V<V<V<int>>> preC(n + 1, V<V<int>>(k + 2, V<int>(mod + 1)));
V<V<V<int>>> preH(n + 1, V<V<int>>(k + 2, V<int>(mod + 1)));
int H = 0; // 计算原串 Hash 值
for (auto c: s) H = (H * base + c - 'a' + 1) % mod;
f[0][0][0] = 1;
for (int i = 0; i < n; i++)
for (int j = 0; j <= k; j++)
for (int x = 0; x < mod; x++)
if (f[i][j][x]){
for (int c = 'a', nxt; c <= 'z'; c++) {
nxt = (x * base + c - 'a' + 1 + mod) % mod;
if (c == s[i]) {
f[i + 1][j + 1][nxt] = 1;
preC[i + 1][j + 1][nxt] = c;
preH[i + 1][j + 1][nxt] = x;
} else {
f[i + 1][j][nxt] = 1;
preC[i + 1][j][nxt] = c;
preH[i + 1][j][nxt] = x;
}
}
}
if (!f[n][k][H]) {
cout << "-1\n";
return;
}
string res = "";
for (int i = n, j = k, x = H; i >= 1; i--) {
res += (char) preC[i][j][x];
if (preC[i][j][x] == s[i - 1]) x = preH[i][j][x], j--;
else x = preH[i][j][x];
}
reverse(res.begin(), res.end());
cout << res << "\n";
}
int32_t main() {
int t;
cin >> t;
for (; t; t--)
solve();
}
G MoonLight的冒泡排序难题
打表找规律,发现分子的数列是\(0,1,7,46,326,2556,\cdots\),然后查到分子的值的递推式是\(a_i=a_{i-1}\times i + (i-1)(i-1)!\)
分子其实就是全排列
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int power( int x , int y ){
int ans = 1;
while( y ){
if( y & 1 ) ans = ans * x % mod;
x = x * x % mod , y >>= 1;
}
return ans;
}
int inv( int x ){
return power( x , mod - 2 );
}
const int N = 2e5+5;
int32_t main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
vector<int> fact(N+1) , invFact(N+1) , f(N+1);
fact[0] = 1 , invFact[0] = inv( fact[0] );
for( int i = 1; i <= N ; i ++ )
fact[i] = fact[i-1] * i % mod , invFact[i] = inv(fact[i]);
f[1] = 0;
for( int i = 2 ; i <= N ; i ++ )
f[i] = ( f[i-1]*i % mod + (i-1)*fact[i-1] % mod ) % mod;
int t ;
cin >> t;
while( t -- ){
int x;
cin >> x;
cout << f[x] * invFact[x] % mod << "\n";
}
return 0;
}
/*
* 0 1 7 46 326 2556 22212 212976
*/