题解
我爱城科软协!
https://ac.nowcoder.com/acm/contest/72285/A
CCST校赛题解
第一题
签到题,按照题目要求输出即可。
//c++
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "欢迎各位参赛者参加本次校内选拔赛!" << endl;
return 0;
}
第二题
统计AC出现的次数,输出 AC/n*100%即可,注意不要对AC/n进行int计算。 比如3/5 * 100 = 0
//c++
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<limits>
#include<unordered_map>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<numeric>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
double cnt = 0;
cin >> n;
string s;
for (int i = 0; i < n; i++) {
cin >> s;
if (s == "AC")
cnt++;
}
cout << (int)(cnt / n * 100) << "%";
return 0;
}
第三题
模拟题,按照题目输入,给出每个点的得分,累加得分输出即可。
//c++
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int ans = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
char c;
std::cin >> c;
if (c == 'X') {
ans += std::min({i + 1, 10 - i, j + 1, 10 - j});//(i,j)的得分
}
}
}
std::cout << ans << "\n";
}
int main() {
int t = 1;
//std::cin >> t;
while (t--) {
solve();
}
return 0;
}
第四题
由题易得中间数为(n * n+1)/2,幻和为中间数 * n
#include <bits/stdc++.h>
using namespace std;
void solve()
{
long long n;
cin >> n;
long long t = n;
n = n*n;
long long sum = (n+1)/2;
cout << sum*t << " " << sum << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while(t--)
solve();
return 0;
}
第五题
(位运算)顾客需要n大小的蛋糕,那么我们要烤的蛋糕一定是大于等于n的
我们看n是否为2的负整数次幂,如果是那就直接输出,且切割次数为0,否则,输出n最高二进制位数的上一位。那最小切割次数就是最低位和最高位的差。
#include <bits/stdc++.h>
using namespace std;
int lowbit(int x)
{
return x & -x;
}
void solve()
{
// 1000 - 0110 = 001
// 1000 >> 1 ans += 2;
// 1000 - 0101
int k;
cin >> k;
int tmp = k;
bool flag = true;
int minp;
int maxp = 0;
while(k != 0)
{
maxp ++;
if(k & 1 && flag)
{
flag = false;
minp = maxp;
}
k >>= 1;
}
if(tmp == lowbit(tmp)) cout << lowbit(tmp) << " " << 0 << endl;
else cout << (1 << maxp) << " " << maxp + 1 - minp << endl;
}
int main()
{
int t = 1;
//cin >> t;
while(t--)
solve();
return 0;
}
第六题
题目大意就是找到一个质数,使与题目给出的质数相加后不是质数。
答案有很多种,其实输出自身就是一种答案,另外7与任何质数相加都为非质数,其他的也可以枚举质数出结果。
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n;
cin >> n;
cout << n << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
//cout.precision(10); cout.setf(ios::fixed);
int t = 1;
//cin >> t;
while(t--)
solve();
return 0;
}
第七题
我们可以得出答案一定具有单调性,因此考虑二分。
check一下高度是否能把题目给出的水都装下,通过二分就能找到最大h
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL n,m;
vector<LL> v;
void solve()
{
cin >> n >> m;
v.clear();
v.resize(n);
for(int i = 0 ; i < n ; i ++) cin >> v[i];
LL l = 0 , r = 1e10;//r要高一些,考虑珊瑚柱全为1e9的平铺情况
LL total = 0;
while(l < r)
{
LL mid = (l + r + 1)/2;
total = 0;
for(int i = 0 ; i < n ; i ++)
{
if(mid > v[i]) total += mid - v[i];
}
if(total <= m) l = mid;
else r = mid - 1;
}
cout << r << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
//cout.precision(10); cout.setf(ios::fixed);
int t = 1;
//cin >> t;
while(t--)
solve();
return 0;
}
第八题
题目数据范围很小,爆搜就好,用全局ans记录最大值。
#include <bits/stdc++.h>
using namespace std;
const int N=100;
struct st
{
int x,y,z,w;
}k[N];
int n,a,b,c;
int sum;
void dfs(int id,int x1,int y1,int z1,int w1)
{
if(id>n)return;
if(x1>a||y1>b||z1>c) return;
if(x1<=a&&y1<=b&&z1<=c)
{
sum=max(sum,w1);
}
dfs(id+1,x1+k[id].x,y1+k[id].y,z1+k[id].z,w1+k[id].w);
dfs(id+1,x1,y1,z1,w1);
}
int main()
{
cin>>n>>a>>b>>c;
for(int i=0;i<n;i++)
cin>>k[i].x>>k[i].y>>k[i].z>>k[i].w;
dfs(0,0,0,0,0);
cout<<sum<<endl;
return 0;
}
第九题
根据题意,有两种情况:
1,以H-2r为圆柱的周长,W为圆柱的高,条件:
H-2r>=2πr
=> H>=2πr+2r => r <= H/2(π+1)
体积:V=πr²W;
2,以W为圆柱的周长,H-2r为圆柱的高,条件:
W>=2πr => r <=W/2π
体积:V = πr²(H-2r)
取max即可
#include <bits/stdc++.h>
using namespace std;
long double PI = acos(-1);//快速获取最精确的PI值
void solve()
{
double w, h, r, result1, result2;
while(scanf("%lf%lf", &w, &h) == 2 && w != 0)
{
r = w / (2 * PI);//第一种情况
result1 = PI * r * r * (h - 2 * r);
r = h / (2 * PI + 2);
r = r * 2 > w ? w / 2 : r;//第二种情况
result2 = PI * r * r * w;
printf("%.3f\n", result1>result2 ? result1:result2);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
//cout.precision(10); cout.setf(ios::fixed);
int t = 1;
//cin >> t;
while(t--)
solve();
return 0;
}
第十题
状态机DP
如果不考虑限制的话,其实每一个位置都有26种选择。
考虑f[i,4]
f[i,0]表示以i字符结尾,最后一个字符是除"Q","A"外任意一个字符;
f[i,1]表示以i字符结尾,最后一个字符以"Q"结尾;
f[i,2]表示以i字符结尾,最后两个字符是"QA"结尾;
f[i,3]表示以i字符结尾,最后一个字符任意且出现过"QAQ"的情况。
那么状态转移就是这样:
f[i][0] += f[i-1][0]*25 + f[i-1][1]*24 + f[i-1][2]*25;
f[i][1] += f[i-1][0] + f[i-1][1];
f[i][2] += f[i-1][1];
f[i][3] += f[i-1][2] + f[i-1][3]*26;
对于每个长度就是f[n,3]
void solve()//这里只放个solve函数,自行取模
{
int t;
cin >> t;
f[0][0] = 1;
for(int i = 1 ; i < N ; i ++)
{
f[i][0] += f[i-1][0]*25 + f[i-1][1]*24 + f[i-1][2]*25;
f[i][1] += f[i-1][0] + f[i-1][1];
f[i][2] += f[i-1][1];
f[i][3] += f[i-1][2] + f[i-1][3]*26;
}
while(t--)
{
int n;
cin >> n;
cout << f[n][3] << endl;
}
}
第十一题:
数据结构区间最小值,线段树,ST表,滑动窗口都可以做。
//线段树
#include <bits/stdc++.h>
using namespace std ;
typedef long long LL ;
const int N = 1e6 + 10 ;
int n, k ;
int w[N] ;
struct Node
{
int l, r, mn ;
}tr[4 * N] ;
void pushup(int u)
{
tr[u].mn = min(tr[u << 1].mn, tr[u << 1 | 1].mn) ;
}
void build(int u, int l, int r)
{
if (l == r) tr[u] = {l, r, w[r]} ;
else
{
tr[u] = {l, r} ;
int mid = l + r >> 1 ;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r) ;
pushup(u) ;
}
}
int query(int u, int l, int r)
{
if (l <= tr[u].l && r >= tr[u].r) return tr[u].mn ;
int mid = tr[u].l + tr[u].r >> 1 ;
int res = 0x3f3f3f3f ;
if (l <= mid) res = min(res, query(u << 1, l, r)) ;
if (r > mid) res = min(res, query(u << 1 | 1, l, r)) ;
return res ;
}
int main()
{
ios::sync_with_stdio(false) ;
cin >> n ;
for (int i = 0 ; i < n ; i ++ )
cin >> w[i] ;
build(1, 0, n - 1) ;
cin >> k ;
for (int i = 0 ; i < n ; i ++ )
cout << query(1, max(0, i - k), min(n - 1, i + k)) << " " ;
return 0 ;
}
//ST表
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10, M = 20;
int n, k, t;
int q[N];
int f[N][M];
int query(int l, int r) {
int len = log(r - l + 1) / log(2);
int x = f[l][len], y = f[r - (1 << len) + 1][len];
return q[x] > q[y] ? y : x;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) scanf("%d", &q[i]);
cin >> k;
t = log(n) / log(2);
for (int j = 0; j <= t; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
if (!j) f[i][j] = i;
else {
int l = f[i][j - 1], r = f[i + (1 << (j - 1))][j - 1];
if (q[l] > q[r]) f[i][j] = r;
else f[i][j] = l;
}
}
}
int l, r;
for (int i = 1; i <= n; i++) {
l = max(1, i - k), r = min(n, i + k);
cout << q[query(l, r)] << " ";
}
cout << endl;
return 0;
}
//双向滑动窗口
#include <bits/stdc++.h>
using namespace std;
const int N=1000010;
int a[N],ans1[N],ans2[N]; //ans1[]存储每个元素前k个(包含自己)元素中的最小值,ans2[]存储每个元素后k个元素(包含自己)元素中的最小值
int q1[N],q2[N];
int n,k;
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>k;
int hh=0,tt=-1;
//窗口从前往后滑动,每次窗口中的最小值代表的是窗口中末元素前k个(包含自己)的最小值
for(int i=1;i<=n;i++){
while(hh<=tt&&q1[hh]<i-k) hh++;
while(hh<=tt&&a[q1[tt]]>=a[i]) tt--;
q1[++tt]=i;
ans1[i]=a[q1[hh]];
}
hh=0,tt=-1;
reverse(a+1,a+n+1); //我们为了方便可以复用上面的代码,将数组反转
//窗口也是从前往后滑动,因为已将数组反转,所以每次窗口中的最小值代表的是窗口中末元素前k个(包含自己)的最小值 ,也就是原序列中该元素后k个(包含自己)的最小值
for(int i=1;i<=n;i++){
while(hh<=tt&&q2[hh]<i-k) hh++;
while(hh<=tt&&a[q2[tt]]>=a[i]) tt--;
q2[++tt]=i;
ans2[n-i+1]=a[q2[hh]];
}
for(int i=1;i<=n;i++) cout<<min(ans1[i],ans2[i])<<' '; //该元素前k个元素和后k个元素(包含自己)中的最小值,即[i-k,i+k]中的最小值
return 0;
}
第十二题
对唐三用bfs跑一个最短路,对比比东跑一个附近环,看唐三能不能比比比东先到附近环。
#include <bits/stdc++.h>
using namespace std;
#define all(c) (c).begin(), (c).end()
#define rall(x) (x).rbegin(), (x).rend()
#define sz(x) (int)(x).size()
#define Sum(a) accumulate((a).begin(), (a).end() , 0ll)
#define Min(a) *std::min_element((a).begin(), (a).end())
#define Max(a) *std::max_element((a).begin(), (a).end())
#define rev(a) reverse((a).begin(), (a).end())
#define each(x, a) for(auto& x : a)
#define mst(a, x) memset(a, x, sizeof(a))
#define LL long long
#define rep(i, from, to) for(ll i = from;i<to;i++)
#define rrep(i, from, to) for(ll i = from;i>to;i--)
#define to_uni(a) a.erase(unique(begin(a), end(a)), end(a))
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pp pop_back
#define endl "\n"
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int mod = 1e9 + 7;
const int P = 998244353;
const int INF = 0x3f3f3f3f;
const int dx[4]={1, 0, -1, 0}, dy[4]={0, 1, 0, -1};
const int fx[8] = {-1, -1, 0, 1, 1, 1, 0, -1}, fy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
const int N = 2e5 + 10 , M = 2e6;
int ne[M],e[M],h[N],idx;
int n,a,b;
int root;
void add(int a , int b)
{
e[idx] = b, ne[idx] = h[a] ; h[a] = idx++;
}
vector<int> bfs(int x)
{
vector<int> dis(n,-1);
queue<int>q;
q.push(x);
dis[x] = 0;
while(q.size())
{
auto u = q.front();
q.pop();
for(int i = h[u] ; ~i ; i = ne[i])
{
int v = e[i];
if(dis[v] == -1)
{
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
return dis;
}
void dfs(vector<int> &dis,vector<bool> &st,vector<int> &par,vector<int> &dfn,int x)
{
st[x] = true;
for(int i = h[x] ; ~i ; i = ne[i])
{
int j = e[i];
if(!st[j])
{
par[j] = x;
dfn[j] = dfn[x] + 1;
dfs(dis,st,par,dfn,j);
}else if(dfn[j] < dfn[x] - 1) {
for(int k = x ; ; k = par[k])
{
if(root == -1 || dis[root] > dis[k])
root = k;
if(k == j) break;
}
}
}
}
void solve()
{
memset(h,-1,sizeof h);
idx = 0;
cin >> n >> a >> b;
a--,b--;
for(int i = 0 ; i < n ; i ++)
{
int u,v;
cin >> u >> v;
u--,v--;
add(u,v),add(v,u);
}
root = -1;
auto dis = bfs(b);
vector<bool> st(n);
vector<int>par(n),dfn(n);
dfs(dis,st,par,dfn,0);
if(bfs(root)[a] > dis[root]) cout << "YES" << endl;
else cout << "NO" << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
//cout.precision(10); cout.setf(ios::fixed);
int t = 1;
//cin >> t;
while(t--)
solve();
return 0;
}
第十三题
一个有 n 个选项的类似于石头剪刀布游戏,胜负关系为一个环,问每局玩 m 轮的情况下,双方绝顶聪明下获胜的概率。可以发现,在第一轮赢了的情况下,只需要保证后面每一轮都是平局就可以赢。因为不能连续出一样的,所以上一轮如果没有输,就存在必定不会输的选项。所以第一轮赢了一定能赢。如果第一轮是平局的情况,一种比较显然的想法是两人的选项都存在一个只能输或平,一个只能赢或平,只能输或平的选项不严格的劣于只能平或赢的选项,所以不选这个。然后考虑到对方也有可以排除的选项,所以自己的一个选项因为对方的排除变为只能输或平,继续进行排除,多轮后只剩下最初的只能平或赢的选项。所以在第一轮平局的情况下,双方只能继续平局。可以注意到这样的排除选项是不严格的,例如有四个选项,都不能选第四个,这时采取 1/2 的概率选第一个,1/2 的概率选第三个,也可以做到最优的期望,但因为输或平的选项和赢或平的选项只有在平局的情况下才相等,所以类似的决策之间仍然是平局。所以第一轮的获胜概率就是整一局的获胜概率,为 1/n,直接输出即可。
#include"stdio.h"
main()
{
int n,m;
scanf("%d%d",&n,&m);
printf("1");
printf("/%d",n);
}