2023杭电多校第九场 - 2 5 8 12
比赛地址:传送门
赛时过了 4 题,继续加油哈 ~
1002 思维题
1005 模拟题
1008 结论题,但是自己目前没法证明
1012 诈骗题
1002 Shortest path
题意
翻译一下题面
给你数字 1,你可以进行任意次三种操作:
- 将数字 \(i\) 变成 \(i + 1\)
- 将数字 \(i\) 变成 \(2 \times i\)
- 将数字 \(i\) 变成 \(3 \times i\)
问你从数字 1 变成数字 n 的所需要的最少操作次数
$1 \le n \le 10 ^ {18} $
思路
反向考虑问题
可以很轻易地发现能用操作 2 和操作 3 是一定要使用,因为这样绝对比普通的使用操作 1来的操作次数小;当都无法使用时,可以利用操作 1 修正数字使得其可以使用操作 2 和操作 3。我们利用记忆化搜索存下反向搜索的已经到达的点到达 1 时所需要的最少次数即可出答案。
还在思考这样操作的充要性?但是我没法证明捏
代码
//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;
ll n;
unordered_map<ll, ll> q;
int dfs(ll x){
if(x == 1 || x == 0 || q[x]) return q[x];
int t = min(x % 2 + dfs(x / 2) + 1, x % 3 + dfs(x / 3) + 1);
return q[x] = t;
}
void solve(){
cin >> n;
q[1] = 0; q[2] = q[3] = 1;
dfs(n);
cout << q[n] << '\n';
return ;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
cin >> _;
while(_ --){
solve();
}
return 0;
}
1005 List Reshape
题意
阿巴阿巴,自己看题吧,看完就懂了
思路
模拟题意即可
代码
//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;
string ss;
vector<int> num;
void out(int l, int r){
cout << "[";
for(int i = l; i <= r; ++ i){
cout << num[i];
if(i < r) cout << ", ";
}
cout << "]";
return ;
}
void solve(){
getchar();
getline(cin, ss);
num.clear();
num.push_back(0);
int x = 0, y;
for(auto c : ss){
if(c == ' ' || c == '['){
x = 0;
continue;
}else if(c == ',' || c == ']'){
num.push_back(x); x = 0;
}else{
x = x * 10 + c - '0';
}
}
cin >> x >> y;
cout << '[';
for(int i = 1, j = y; i <= x * y; i += y, j += y){
out(i, j);
if(j == x * y) cout << "]";
else cout << ", ";
}
cout << endl;
return ;
}
signed main(){
// ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
cin >> _;
while(_ --){
solve();
}
return 0;
}
1008 Coins - 不会证明qwq
题面
不记题面了,自己看题面吧~
思路
仅摘记答案
答案为 $\displaystyle \sum_{i = 1}^{n} \sum_{j = i + 1}^{n} a_i a_j $
代码
ll n, a[maxm];
inline void print(__int128_t n){
if(n < 0){
putchar('-');
n*=-1;
}
if(n > 9) print(n / 10);
putchar(n % 10 + '0');
}
void solve(){
cin >> n;
__int128_t ans = 0;
for(int i = 0; i < n; ++ i){
cin >> a[i];
}
for(int i = 0; i < n - 1; ++ i){
ans += a[i] * a[i + 1];
a[i + 1] += a[i];
}
print(ans);
cout << '\n';
return ;
}
1012 Inference
题意
给你 n 个人每个人的 m 个特征数据,再给你 Alice 的前 m - 1 个特征值,特征值的可能取值为0, 1, 2。请你由给出的公式(见 hdu 题面)判断 Alice 的最后一个特征值取 0,1,2 中的哪个数字的可能性最大?
思路
诈骗题!
理解题意之后可以发现,这题的难点就在读懂题面。问的是最后取哪个值的可能性最大?观察到给出的式子中,影响最终概率大小的只有式子 \(P(x_m | \pi(x_m))\),而这个就是个条件概率,所以其实这题根本用不着求概率,我们只需要统计在 n 个人中 $\pi(x_m) $ 所包含的特征值均相等的人中,\(x_m\)里 012 出现的次数,最终哪个数字出现的次数越多,那么那个就是最终的答案
表述可能不太好理解,还是看题面吧
代码
//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;
void solve(){
int n, m, k;
cin >> n >> m >> k;
vector<int> e[n + 1];
for(int i = 0; i < k; ++ i){
int x, y; cin >> x >> y;
e[y].push_back(x);
}
int f[n + 1][m + 1];
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= m; ++ j){
cin >> f[i][j];
}
}
vector<int> p(m + 1);
for(int i = 1; i < m; ++ i) cin >> p[i];
vector<int> cnt(3, 0);
for(int i = 1; i <= n; ++ i){
bool flag = true;
for(auto x : e[m]){
if(f[i][x] != p[x]){
flag = false; break;
}
}
if(flag) ++ cnt[f[i][m]];
}
int ans = 0;
if(cnt[1] > cnt[ans]) ans = 1;
if(cnt[2] > cnt[ans]) ans = 2;
cout << ans << '\n';
return ;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
cin >> _;
while(_ --){
solve();
}
return 0;
}