2025ccpc女生赛题解
补题链接 : https://qoj.ac/contest/2564
J. 后鼻嘤
在每个以 n 结尾的字符串后添加 g 并输出
读入一整行法
//2025-11-02
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;
const int N = 1e5+10;
#define LL long long
void solve() {
char s[N];
cin.getline(s,100000);
for(int i=0;;i++) {
if((s[i]>'z'||s[i]<'a')&&s[i]!=' ') break;
cout<<s[i];
if(s[i]=='n'&&(s[i+1]>'z'||s[i+1]<'a'))
cout<<'g';
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
solve();
return 0;
}
持续读⼊字符串法
//2025-11-02
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;
#define LL long long
void solve() {
char s[10];
bool flag=0;
while(cin>>s) {
if(flag) {
cout<<" ";
}
flag=1;
int n=strlen(s);
cout<<s;
if(s[n-1]=='n') cout<<'g';
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
solve();
return 0;
}
A.环状线
简单的分类讨论。
暴力模拟也可以通过。
//2025-11-02
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;
int n,s,t;
bool solve() {
int dis1,dis2;
if(s<t) {
dis1=t-s;
dis2=n-(t-s);
}else{
dis1=n-(s-t);
dis2=s-t;
}
return dis1<dis2;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin>>n>>s>>t;
puts(solve()?"1":"2");
return 0;
}
G. 最大公约数
从\([1,n]\)中选出\(k\)个不同的整数,使得两两互质。
贪心,筛出小于\(n\)的素数(设有\(cntp\)个),那么\([1,n]\)中最多有\(cntp+1\)个数两两互质(1和任意数互质)
线性筛的模板。
//2025-11-02
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;
const int N = 5e5+10;
#define LL long long
int n,k;
int prime[N], mindiv[N];
int cntp;
void Euler(int n) {
for (int i = 2; i <= n; i++) {
if (!mindiv[i])
mindiv[i] = prime[++cntp] = i;
for (int j = 1; j <= cntp && i * prime[j] <= n && prime[j] <= mindiv[i]; j++)
mindiv[i * prime[j]] = prime[j];
}
}
void solve() {
cin>>n>>k;
Euler(n);
prime[0]=1;
if(k<=cntp+1) {
cout<<"YES"<<endl;
for(int i=0;i<k;i++) {
cout<<prime[i]<<" ";
}
}else{
cout<<"NO"<<endl;
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
solve();
return 0;
}
C. 短视频
模拟,\(O(n)\)遍历每个视频即可
设当前累积的观看时长为sum
注意:每个视频都会至少看1s,因为是在这1s结束后判断是否继续刷。
//2025-11-02
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;
const int N = 2e5+10;
#define LL long long
LL n,T;
LL t[N],k[N];
LL sum;
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin>>n>>T;
for(int i=1;i<=n;i++) {
cin>>t[i]>>k[i];
}
for(int i=1;i<=n;i++) {
if(sum<=T-t[i]) sum+=t[i];//累计不超T
else{
if(sum-T<=k[i]-t[i]) sum+=t[i];//吸引力足够支撑到视频结束
else
sum=max(sum+1,T+k[i]+1);//吸引力中间不足
}
}
cout<<sum;
return 0;
}
K. 左儿子右兄弟
这道题想起来比较简单,代码实现有些细节不好写。
题目有两问:
-
所有节点子树大小之和最小是多少
-
满足1有几种情况
对于1,显然是每个点子树和最大的点排在前面(因为排在越后面,深度越大,统计子树和时累加次数越多)
如果一个点的几个儿子的子树大小相等,相等的这几个顺序可以是任意的,这就形成了多种情况,也就是第二问让求的。假设有\(k\)个子树大小都为\(w\)的儿子,那么方案数就乘\(k!\),dfs时统计方案数即可。
首先原树建图后dfs求各点的子树和siz。
第一问:dfs回溯时给当前点u的所有儿子的siz排序(大到小),最大的\(k_1\)做u的儿子,然后\(k_2\)做\(k_1\)的儿子,依次……建一个新树。然后dfs新树求各点的新子树和ans,再加和即为答案res1。
第二问:记结果为res2,刚才排序后,直接统计每个子树大小的有几个,然后乘\(k!\)。
//2025-11-03
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;
const int N = 2e5+10;
#define LL long long
const LL mod=998244353;
int n;
int to[N],nxt[N],hd[N],ecnt;
void add(int x,int y) {
to[++ecnt]=y;nxt[ecnt]=hd[x];hd[x]=ecnt;
}
vector<int>g[N];//新图
LL siz[N];
LL fac[N];//阶乘
LL res1,res2=1;
struct node{
int u;
LL size;
node(int uu,LL s):u(uu),size(s){}
bool operator < (const node& x)const{
return size>x.size;
}
};
vector<node>ve[N];
void dfs(int x,int fa) {
for(int i=hd[x];i;i=nxt[i]) {
int& y=to[i];
dfs(y,x);
ve[x].push_back(node(y,siz[y]));
siz[x]+=siz[y];
}
if(ve[x].empty()) return;
sort(ve[x].begin(),ve[x].end());
int pre=x,cnt=1;
for(auto k:ve[x]) {
if(k.size==siz[pre]&&pre!=x) {
cnt++;
}
else{
res2=res2*fac[cnt]%mod;
cnt=1;
}
g[pre].push_back(k.u);
pre=k.u;
}
res2=res2*fac[cnt]%mod;
}
LL siz2[N];
void getRes1(int x,int fa) {
for(auto y:g[x]) {
getRes1(y,x);
siz2[x]+=siz2[y];
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin>>n;
int x;
fac[0]=1;
for(int i=1;i<=n;i++) {
siz[i]=1;
siz2[i]=1;
fac[i]=fac[i-1]*i%mod;
}
for(int i=2;i<=n;i++) {
cin>>x;
add(x,i);
}
dfs(1,0);
getRes1(1,0);
for(int i=1;i<=n;i++)
res1=res1+siz2[i];
//注意res1不用取模
cout<<res1<<"\n"<<res2;
return 0;
}
B. 爬⼭
分层图最短路。
首先很容易想到是最短路,然后看到疲劳值清空,H很小,就能联想到分层图了。
按照疲劳值建H+1层图即可。
对于每条边:
上坡,在不超过H的情况下,从当前层连到上坡后对应疲劳值层;
下坡,从当前层到第0层连边。
//2025-11-09
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 2e6;
const int M = 2e7;
#define LL long long
const LL inf = 1e18;
int n, m, H;
int h[N];
int to[M], nxt[M], hd[N], ecnt;
LL w[M];
void add(int x, int y, LL z) {
to[++ecnt] = y;
w[ecnt] = z;
nxt[ecnt] = hd[x];
hd[x] = ecnt;
}
struct node {
int u;
LL val;
node() {}
node(int uu, LL vv): u(uu), val(vv) {}
bool operator < (const node&x) const {
return val > x.val;
}
};
priority_queue<node> q;
LL dis[N];
bool vis[N];
void dij(int s) {
for (int i = 1; i <= (H + 1) * n; i++) dis[i] = inf;
q.push(node(s, 0));
dis[s] = 0;
while (!q.empty()) {
int x = q.top().u;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = hd[x]; i; i = nxt[i]) {
int& y = to[i];
if (dis[y] > dis[x] + w[i]) {
dis[y] = dis[x] + w[i];
q.push(node(y, dis[y]));
}
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> H;
for (int i = 1; i <= n; i++) cin >> h[i];
for (int i = 1, u, v, t; i <= m; i++) {
cin >> u >> v >> t;
if (h[u] > h[v]) {
for (int j = 0; j <= H; j++) {
add(u + j * n, v, t); // 下坡
if (j + (h[u] - h[v]) <= H)
add(v + j * n, u + (j + (h[u] - h[v])) * n, t); // 上坡
}
} else if (h[u] < h[v]) {
for (int j = 0; j <= H; j++) {
add(v + j * n, u, t); // 下坡
if (j + (h[v] - h[u]) <= H) {
add(u + j * n, v + (j + (h[v] - h[u])) * n, t); // 上坡
}
}
} else {
// 平路
for (int j = 0; j <= H; j++) {
add(u + j * n, v + j * n, t);
add(v + j * n, u + j * n, t);
}
}
}
dij(1);
for (int i = 2; i <= n; i++) {
LL ans = inf;
for (int j = 0; j <= H; j++)
ans = min(ans, dis[j * n + i]);
if (ans != inf)
cout << ans << " ";
else
cout << "-1 ";
}
return 0;
}
其他题目待补。。。

浙公网安备 33010602011771号