Loading

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. 所有节点子树大小之和最小是多少

  2. 满足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;
}

其他题目待补。。。

posted @ 2025-11-10 00:16  AuroraKelsey  阅读(5)  评论(0)    收藏  举报