2022年华中科技大学程序设计新生赛
背景:之前练的一场忘了写题解,补一下,赛时过了6题
A
解析
主要考察的是对于期望dp的理解
其实也没什么好说的,一般写过期望dp的还是很容易想到
这里就把官方的贴上来了
补充一下:期望dp一般设状态都是距离目标状态的期望,然后从目标状态倒过来递推
\(dp[i][j]的期望 = 下一个可能状态的综合期望 + 自己本身的期望 (指1)\)
代码
// ξ†(ᗜ ˰ ᗜ)†ξ
// 去吧,鸭鸭,把希儿和AC都带回来!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int M = 998244353;
int dp[1005][1005];
int qmi(int a,int b){
int res = 1;
while(b){
if(b & 1){
res = res * a % M;
}
a = a * a % M;
b >>= 1;
}
return res;
}
int a[1005];
int x[1005];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
int p = qmi(100,M-2);
for(int i = 1; i <= n; i++){
cin >> a[i] >> x[i];
}
for(int i = 1; i <= 1000; i++) dp[n][i] = 0;
for(int i = n-1; i >= 0; i--){
for(int j = 1000; j >= 0; j--){
if(j == a[i+1]){
dp[i][j] = (dp[i+1][j] + 1) % M;
}
else if(j > a[i+1]){
dp[i][j] = ((1 + (dp[i+1][j-1] * x[i+1]) % M * p) % M + ((100 - x[i+1]) * p) % M * dp[i+1][j] % M) %M;
}
else {
dp[i][j] = (qmi(x[i+1],M-2)*100 % M + dp[i][j+1]) % M;
}
}
}
cout << dp[0][0] << endl;
return 0;
}
C
解析
签到,观察一下可以发现答案是 \((a+b) \over b\)
代码
// ξ†(ᗜ ˰ ᗜ)†ξ
// 去吧,鸭鸭,把希儿和AC都带回来!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
int gcd(int a,int b){
if(b == 0) return a;
else
return b > a ? gcd(b,a) : gcd(b,a % b);
}
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
void solve(){
int a,b;
cin >> a >> b;
int p = gcd(a,b);
a = a / p;
b = b / p;
a = a + b;
cout << a << "/" << b << endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}
E
解析
贪心,发现合并石子每次让最大的两个合并一定不会使结果变差,用优先队列可以解决
代码
// ξ†(ᗜ ˰ ᗜ)†ξ
// 去吧,鸭鸭,把希儿和AC都带回来!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e5 + 5;
int s[N];
priority_queue<int> pri;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for(int i = 1; i <= n; i++) cin >> s[i],pri.push(s[i]);
int res = 0;
while(pri.size() != 1){
int p = pri.top();
pri.pop();
int q = pri.top();
pri.pop();
res = res + p * q;
pri.push(p+q);
}
cout << res << endl;
return 0;
}
H
解析
签到,模拟即可
代码
// ξ†(ᗜ ˰ ᗜ)†ξ
// 去吧,鸭鸭,把希儿和AC都带回来!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
string s;
int n;
cin >> n;
cin >> s;
int res = 0;
int cnt = 0;
for(int i = 0; i < n; i++){
if(s[i] == 'f'){
res = 1;
}
else if(s[i] == 'y'){
if(res == 1){
res++;
}
else res = 0;
}
else if(s[i] == 't'){
if(res == 2){
res++;
cnt++;
}
else res = 0;
}
else res = 0;
}
cout << cnt << endl;
return 0;
}
J
解析
博弈+思维
分几种情况考虑
- Walk Alone的横坐标大于或等于另一个玩家的横坐标,这时walk alone可以一直斜向上或斜向下走,而另一个玩家的最优走法也是这样,所以他永远追不上Walk Alone
- Walk Alone的横坐标小于另一个玩家的横坐标
- 他们的纵坐标不等,同样Walk Alone 一直斜着走,而另一个玩家无论怎么走他与Walk ALone 的纵坐标至少相差1以上,所以他永远追不上Walk Alone
- 他们的纵坐标相等,这时Walk Alone 无论怎么走,另一个玩家的最优走法是朝着Walk Alone 的方向走
如图所示,红色是Walk ALone 走的路程,蓝色是另一个玩家走的路程,可见下一次移动另一个玩家就能抓到Walk ALone
横着走结局也是一样都是另一个玩家赢
这时是两个玩家横坐标之差是偶数的时候
如果两个玩家横坐标之差是奇数,那么红方就可以将蓝色方吃掉,最后依然是红色方赢
那么答案就显而易见了
代码
// ξ†(ᗜ ˰ ᗜ)†ξ
// 去吧,鸭鸭,把希儿和AC都带回来!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
void solve(){
int a,b,c,d;
cin >> a >> b >> c >> d;
if(a >= c){
cout << "Walk Alone" << endl;
}
else {
if(b != d){
cout << "Walk Alone" << endl;
}
else {
int p = c - a;
if(p % 2 == 0){
cout << "Salix Leaf" << endl;
}
else cout << "Walk Alone" << endl;
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}
L
解析
简单贪心,可以发现,当后续的曲子都置为Perfect时不会使结果变差
代码
// ξ†(ᗜ ˰ ᗜ)†ξ
// 去吧,鸭鸭,把希儿和AC都带回来!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
double n,k;
cin >> n >> k;
double per = 900000/n;
double goo = 585000/n;
double noww = 0;
int maxx = 0;
int cnt = 0;
for(int i = 1; i <= k; i++){
string s;
cin >> s;
if(s == "perfect"){
cnt++;
noww += per;
}
else if(s == "good"){
cnt++;
noww += goo;
}
else {
maxx = max(maxx,cnt);
cnt = 0;
}
}
for(int i = k+1; i <= n; i++){
cnt++;
noww += per;
}
maxx = max(maxx,cnt);
noww += 100000 * maxx / n;
noww += 0.5;
int res = noww;
cout << res << endl;
return 0;
}
N
解析
构造题,也是分情况来进行构造
- a % 3 == 0 && a % 2 == 0 这时候我们直接构造 3a 和 2a 即可,这样可以直接保证两个条件,构造出来的两个数因子和原来一样
- a % 3 != 0 && a % 2 != 0 这时候也和上面一样,构造出来的两个数分别多了2和3的因子
- a % 3 != 0 && a % 2 == 0 构造 a 和 2a 构造出来的两个数因子和原来一样
- a % 3 == 0 && a % 2 != 0
这个情况也是最难想的情况,这个数不能被2整除,说明其是一个奇数。
那么我们可以先找到这个数内第一个没出现过的质因子,根据数据范围可以知道这个因子一定不会超过100,设其为prime。
可以知道prime一定是一个奇数,那么prime+1一定为偶数,并且prime+1一定也不是a的因子(如果它是a的因子,那么a一定能被2整除)
$所以构造prime \times a 和 (prime + 1) \times a $ 即可
代码
// ξ†(ᗜ ˰ ᗜ)†ξ
// 去吧,鸭鸭,把希儿和AC都带回来!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
int prime[105];
bool vis[105];
int ans;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
void solve(){
int a;
cin >> a;
if(a % 3 == 0 && a % 2 == 0){
cout << a * 2 << " ";
cout << a * 3 << endl;
}
else if(a % 3 != 0 && a % 2 != 0){
cout << a * 2 << " ";
cout << a * 3 << endl;
}
else if(a % 3 != 0 && a % 2 == 0){
cout << a << " ";
cout << a * 2 << endl;
}
else{
int prim = 0;
for(int i = 1; i <= 8; i++){
if(a % prime[i] != 0){
prim = prime[i];
break;
}
}
cout << a * prim << " ";
cout << a * (prim + 1) << endl;
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int x = 100;
for(int i = 2; i <= x; i++)
{
if(!vis[i]) prime[ans++] = i;//判断是否是素数
for(int j = 0; prime[j] <= x / i;++j)
{
vis[prime[j] * i] = true;//最小质因数和最大因子的乘积
if(i % prime[j] == 0) break;//说明不是最小质因数
}
}
int res = 1;
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}