27th CCF CSP | 第27次专业级软件能力认证 游记&题解

游记

前言

第一次参加专业级 CSP,上大学了还要继续与 CCF 打交道。

试卷 pdf 排版和 CSP-J/S,NOIP 一模一样,有过去的味道了。


题解

Score

100 + 100 + 100 + 30 + 70 = 400

提前 40 分钟交卷出场。

排名:39

A 如此编码

概述

得分 100,1A

通过时间:+5 min

题解

一开始不会,直到看到提示。

提示给出如下公式:

mmodci=j=1i1cj×bj+1

作差,除去 cj 即可。

Codes

#include<bits/stdc++.h>
using namespace std;
template <typename Tp>
void read(Tp &x) {
x = 0; int fh = 1; char ch = 1;
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') fh = -1, ch = getchar();
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= fh;
}
const int maxn = 20 + 7;
int n, m;
int a[maxn], c[maxn], b[maxn];
void Init(void) {
read(n); read(m); c[0] = 1;
for(int i = 1; i <= n; i++) {
read(a[i]);
c[i] = c[i - 1] * a[i];
}
}
void Work(void) {
for(int i = 1; i <= n; i++) {
int tmp = m % c[i] - m % c[i - 1];
b[i] = tmp / c[i - 1];
}
for(int i = 1; i <= n; i++) {
printf("%d%c", b[i], " \n"[i == n]);
}
}
signed main(void) {
Init();
Work();
// system("pause");
return 0;
}

B 何以包邮?

概述

得分:100,1A

通过时间:+11 min

简要题意

给出 {an},选出一个子序列 {bn},使得 biM,求 minbi

数据范围 n30,ai104

题解

S=ai

显而易见可以用 01 背包求出 0S 每一个容量的可达性,从 M 向后枚举直至得到答案即可。

时间复杂度 O(ai)

Codes

#include<bits/stdc++.h>
using namespace std;
template <typename Tp>
void read(Tp &x) {
x = 0; int fh = 1; char ch = 1;
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') fh = -1, ch = getchar();
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= fh;
}
const int maxn = 30 + 7;
int n, lim, S;
int a[maxn];
bool dp[500000];
void Init(void) {
read(n); read(lim);
for(int i = 1; i <= n; i++) {
read(a[i]); S += a[i];
}
}
void Work(void) {
dp[0] = true;
for(int i = 1; i <= n; i++) {
for(int j = S; j >= a[i]; j--) {
dp[j] |= dp[j - a[i]];
}
}
for(int i = lim; i <= S; i++) {
if(dp[i]) {
printf("%d\n", i); return ;
}
}
}
signed main(void) {
Init();
Work();
// system("pause");
return 0;
}

C 防疫大数据

概述

恶臭大模拟。

得分:100,1A

通过时间:+59 min

Codes

#include<bits/stdc++.h>
using namespace std;
template <typename Tp>
void read(Tp &x) {
x = 0; int fh = 1; char ch = 1;
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') fh = -1, ch = getchar();
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= fh;
}
const int maxn = 1000 + 7;
struct DayInfo {
int r, m;
int d[maxn], u[maxn], a[maxn];
int rec[maxn];
}info[maxn];
//struct area_danger {
// int date, id;
//};
//
//unordered_map <int, int> inq;
//queue <area_danger> danger;
//
//void RemoveDanger(int D) {
// while(danger.size()) {
// area_danger T = danger.front();
// if(T.date <= D - 7) {
// danger.pop(); inq[T.id]--;
// }
// else break;
// }
//}
//
//void AddDanger(int date, int id) {
// area_danger T; T.date = date, T.id = id;
// danger.push(T); inq[id]++;
//}
//
//bool CheckDanger(int date, int id) {
// if(inq[id] > 0) return true;
// return false;
//}
//vector <int> dangerlist[maxn];
bool CheckDanger(int date, int id) {
for(int i = max(0, date - 6); i <= date; i++) {
for(int j = 1; j <= info[i].r; j++) {
if(info[i].rec[j] == id) return true;
}
}
return false;
}
int n, torec[maxn];
struct Active_User {
int date, id;
};
unordered_map <int, int> user;
queue <Active_User> act;
void RemoveActive(int D) {
while(act.size()) {
Active_User T = act.front();
if(T.date <= D - 7) {
act.pop(); user[T.id]--;
}
else break;
}
}
void AddActive(int date, int id) {
Active_User T; T.date = date, T.id = id;
act.push(T); user[id]++;
}
void Init(void) {
read(n);
for(int nowday = 0; nowday < n; nowday++) {
// RemoveDanger(nowday);
read(info[nowday].r); read(info[nowday].m);
for(int i = 1; i <= info[nowday].r; i++) {
read(info[nowday].rec[i]);
// read(torec[i]); AddDanger(nowday, torec[i]);
}
for(int i = 1; i <= info[nowday].m; i++) {
read(info[nowday].d[i]); read(info[nowday].u[i]); read(info[nowday].a[i]);
}
//date user area
vector <int> userlist;
set <int> inv;
for(int i = max(nowday - 6, 0); i <= nowday; i++) {
for(int j = 1; j <= info[i].m; j++) {
if(info[i].d[j] <= nowday - 7) continue;
if(inv.find(info[i].u[j]) != inv.end()) continue;
bool ok = true;
for(int k = info[i].d[j]; k <= nowday; k++) {
if(CheckDanger(k, info[i].a[j]) == false) {
ok = false; break;
}
}
if(ok) {
userlist.push_back(info[i].u[j]);
inv.insert(info[i].u[j]);
}
}
}
sort(userlist.begin(), userlist.end());
printf("%d ", nowday);
for(auto U : userlist) {
printf("%d ", U);
}
puts("");
}
}
void Work(void) {
}
signed main(void) {
Init();
Work();
// system("pause");
return 0;
}

D 吉祥物设置

概述

得分:30

通过 n10000,m=1 共两档部分分。

正解

对于每一种颜色,共建立 m 棵线段树。

E 高维亚空间超频物质变压缩技术

概述

得分:70

通过 Subtask 1, 2, 3

Subtask 1, 2

n2000

经典 dp,设 f(i) 代表以 1i 合并为若干段的最小代价。

f(i)=min{f(j)+[S(i)S(j)L]2},while mj<mi

其中 S(n)=i=1nvi

时间复杂度为 O(n2)

Subtask 3

n105,保证 m 递增。

去掉了对 mj 的限制,上述式子是个典型的斜率优化。

去掉 min,假设转移点为 jf(i)=f(j)+S(i)22LS(i)2S(i)S(j)+S(j)2+2LS(j)+L2

移项后,有

f(j)+S(j)2+2LS(j)=2S(i)S(j)+f(i)S(i)2+2LS(i)L2

对于一个直线 y=kx+b,即有 y=f(j)+S(j)2+2LS(j),k=2S(i),x=S(j),b=f(i)S(i)2+2LS(i)L2

由于 S(i) 严格单调增,即有 k,x 严格单调增,用优先队列维护决策点即可。

posted @   览遍千秋  阅读(2022)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
历史上的今天:
2019-09-18 LG5338/BZOJ5509/LOJ3105 「TJOI2019」甲苯先生的滚榜 Treap
2019-09-18 LG4516/LOJ2546 「JSOI2018」潜入行动 树上背包
点击右上角即可分享
微信分享提示