CTFPC-3rd 题解
前言#
最高分,@haoertiansuo,一如既往地榜一。由于题目难度大幅提高,没有 AK。分数 365/600 分。
第二名,@yhylivedream,E 题用了大肠腧玄学做法,分数 345/600 分。
第三名,@JOE_ZengYuQiao_0928,275/600 分。
B 题没有超过 10 分之人,D 题没有超过 30 分之人,F 题没有超过 25 分之人。
原因:B 题,正解没人想到。D 题,(可能)数据错误(有好事者可以帮忙看一下 Github 仓库,校验 std 和 gen)。F 题,大模拟,没有人愿意做。
本文很长,推荐右下角展开目录,跳着看。
A. 摆月饼#
神金搜索,秒了。
注意 Sub 里 的特殊情况,要特判。
#include <bits/stdc++.h>
#define rty printf("Yes\n");
#define RTY printf("YES\n");
#define rtn printf("No\n");
#define RTN printf("NO\n");
#define rep(v,b,e) for(int v=b;v<=e;v++)
#define repq(v,b,e) for(int v=b;v<e;v++)
#define rrep(v,e,b) for(int v=b;v>=e;v--)
#define rrepq(v,e,b) for(int v=b;v>e;v--)
#define stg string
#define vct vector
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
void solve() {
}
int n, p[100][100], pre[100];
bool vis[100];
int ans = 0;
void dfs(int dep) {
if (dep == n + 1) {
int res = 0;
rep(i, 1, n) {
res += p[i][pre[i]];
}
if (res > ans) {
ans = res;
}
return;
}
rep(i, 1, n) {
if (!vis[i]) {
vis[i] = 1;
pre[dep] = i;
dfs(dep + 1);
vis[i] = 0;
}
}
}
main() {
// int t; cin >> t; while (t--) solve();
cin >> n;
rep(i, 1, n) {
rep(j, 1, n) {
cin >> p[i][j];
}
}
if (!p[1][1] && n == 20) {
int res = 0;
rep(i, 1, n) {
rep(j, 1, n) {
res = max(res, p[i][j]);
}
}
cout << res << endl;
return 0;
} else if (n == 20) {
int res = 0;
rep(i, 1, n)
res += p[i][1];
cout << res << endl;
return 0;
}
dfs(1);
cout << ans << endl;
return 0;
}
B. 不吉利的素数#
使用注意力集中的左轮眼可以想到:我们先需要做预处理,找到一个足够大的数 ,设一个集合 。对于每一个 且为素数的 ,如果没有任意 互为对方的子序列,将 加入 ,最终可以得到一个序列。如果你的注意力比较涣散,我就直接在这里给出 罢:
手打觉得麻烦的,给出计算她的 Python 代码:
from math import *
def isSub(s: str, t: str) -> bool:
index = 0
for value in s:
index = t.find(value, index)
if index == -1:
return False
index += 1
return True
def isprime(n : int) -> bool:
if n == 2:
return True
for i in range(2, n):
if i * i > n:
break
if n % i == 0:
return False
return True
MS = []
for i in range(2, int(1e8)):
stg = str(i)
flg = 0
if not isprime(i):
continue
if (len(MS)):
for v in MS:
if isSub(v, stg) or isSub(stg, v):
flg = 1
break
if not flg:
MS.append(stg)
else:
MS.append(stg)
print("{", ",".join(MS), "}")
这样输出出来可以直接拿着用。当然,抽象的 Python 会花费您较多的时间(实测 > 60 min,量子计算机和您的 42 号混凝土可能耗时不同),而 C艹也没有较为便捷的实现,有 matlab 等工具的同学自己玩去。
接下来才是主要部分:先扫描字符串,匹配,符合打哨兵符。打一次符号计数器加一,代码:
#include <bits/stdc++.h>
using namespace std;
string stg[10][10] = {
{"2", "3", "5", "7"},
{"11", "19", "41", "61", "89"},
{"409", "449", "499", "881", "991"},
{"6469", "6949", "9001", "9049", "9649", "9949"},
{"60649"},
{"666649"},
{"946669"},
{"60000049", "66000049", "66600049"}
};
int len_stg[10] = {
4, 5, 5, 6, 1, 1, 1, 3
};
int main() {
string s;
int ans = 0;
cin >> s;
for (int j = 0; j < 7; j++) {
for (int i = 0; i < s.size(); i++) {
string init = stg[j][0];
int pt = 0;
while (pt < len_stg[j]) {
for (int k = i; k <= i + j; k++) {
if (s[k] != init[k - i]) {
goto _;
}
}
s[i] = '@';
ans++;
goto __;
_:;
init = stg[j][++pt];
}
__:;
}
}
cout << ans;
}
C. 外婆桥#
Sub1、3()#
暴力,分到手。
Sub2、4()#
数据小,暴力跑得过,所以脑子不动、快读都懒得优化这破题能拿 60 分。
如果你实在懒到抽象, 分也是轻轻松松的好吧。
Sub 5()#
注意到:只有区间查询,没有区间修改,考虑前缀和。
但是或运算无法使用前缀和,它没有其逆运算,与 、 如出一辙。
那么可以想到,它是允许重复计算的,比如要求计算 ,。这是因为一个数被或两次还是能得到这个数。
使用注意力集中的左轮眼能想到,它的性质和 是一样的,如果你 CSP-J 401 分的话,更容易注意到:和 性质一样的算法可以使用包括但不限于:RMQ、ST 表、单调队列、树状数组等算法。
如果你够有实力,能默写 OI-WIKI,使用线段树、分块、ODT、莫队,那我也无以回应。我们这里只考虑更为简易的普通算法,这里附上 ST 表的代码:
#include <bits/stdc++.h>
#define rty printf("Yes\n");
#define RTY printf("YES\n");
#define rtn printf("No\n");
#define RTN printf("NO\n");
#define rep(v,b,e) for(int v=b;v<=e;v++)
#define repq(v,b,e) for(int v=b;v<e;v++)
#define rrep(v,e,b) for(int v=b;v>=e;v--)
#define rrepq(v,e,b) for(int v=b;v>e;v--)
#define stg string
#define vct vector
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
void solve() {
}
#define int ull
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x<0)
putchar('-'),x=-x;
if(x>9)
write(x/10);
putchar(x%10+'0');
return;
}
const int N = 1E6 + 5;
int ST[N][32];
int query(int l, int r) {
int k = log2(r - l + 1);
return ST[l][k] | ST[r - (1 << k) + 1][k];
}
main() {
// int t; cin >> t; while (t--) solve();
int n, q;
n = read(); q = read();
rep(i, 1, n) {
ST[i][0] = read();
}
for (int j = 1; (1 << j) <= n; j++) {
for (int i = 1; i <= n - (1 << (j - 1)) + 1; i++) {
ST[i][j] = ST[i][j - 1] | ST[i + (1 << (j - 1))][j - 1];
}
}
while (q--) {
int l, r;
l = read(); r = read();
write(query(l, r));
putchar('\n');
}
return 0;
}
D. 坐地铁#
Sub1()#
抽象玩意儿,最多一次换乘,数据超级水,为什么我这样说去看 Github 上的 Generator 和数据。
Sub2()#
我们保证一定有解(后来补的)
Sub3()#
其实没屁用这个特殊性质。
Sub4()#
先消去所有线路,对于所有站标记其经过的线路。接着在起点站跑 dfs,数据水,保过:
#include <bits/stdc++.h>
#define rty printf("Yes\n");
#define RTY printf("YES\n");
#define rtn printf("No\n");
#define RTN printf("NO\n");
#define rep(v,b,e) for(int v=b;v<=e;v++)
#define repq(v,b,e) for(int v=b;v<e;v++)
#define rrep(v,e,b) for(int v=b;v>=e;v--)
#define rrepq(v,e,b) for(int v=b;v>e;v--)
#define stg string
#define vct vector
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
void solve() {
}
#define int ll
int res = LLONG_MAX;
vct<int> E[806];
bool vis[30][806];
bool visit[806];
int n, s, t;
void dfs(int u, int line, int times) {
if (u == t) {
res = min(res, times);
return;
}
if (times > res) {
return;
}
for (int v : E[u]) {
if (visit[v]) continue;
if (!vis[line][v]) {
rep(i, 1, n) {
if (vis[i][v]) {
visit[v] = 1;
dfs(v, i, times + 2);
visit[v] = 0;
}
}
} else {
visit[v] = 1;
dfs(v, line, times + 1);
visit[v] = 0;
}
}
}
main() {
// int t; cin >> t; while (t--) solve();
cin >> n >> s >> t;
rep(i, 1, n) {
int ai;
cin >> ai;
int x, last;
cin >> x;
vis[i][x] = 1;
rep(f, 2, ai) {
last = x;
cin >> x;
E[last].push_back(x);
E[x].push_back(last);
vis[i][x]= 1;
}
}
visit[s] = 1;
rep(i, 1, n) {
if (vis[i][s]) {
dfs(s, i, 0);
memset(visit, 0, sizeof visit);
}
}
cout << res * 5;
return 0;
}
E. DFbd 的因子积#
感谢圣人 DFbd 的供题!
暴力()#
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main() {
int p;
cin >> p;
int ans = 1;
for (int i = 1; i < p; i++) {
int tmp = 1;
for (int d = 1; d * d <= i; d++) {
if (d * d == i) {
tmp *= d;
tmp %= p;
} else if (i % d == 0) {
tmp *= i;
tmp %= p;
}
}
ans *= tmp;
ans %= p;
}
cout << ans;
}
正题()#
注意到有:
幂这块用快速幂优化:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int p,ans=1;
int fpow(int a,int b,int p){
int res=1;
while(b){
if(b%2) res=res*a%p;
a=a*a%p;
b/=2;
}
return res;
}
signed main(){
cin >> p;
for(int i=1;i<p;i++) ans=ans*fpow(i,(p-1)/i,p)%p;
cout << ans;
return 0;
}
F. 扑克#
这他妈是道大模拟,所以没人帮我验题,是我自己手工计算的。
倍率 2.5,没骗到的同学可惜咯。
Sub1()#
,自娱自乐。注意到这个人是地主,他必定会赢。输出 ,十分到手。
Sub2()#
只考虑:
- 单牌
- 对子
- 王炸
其它都不用考虑。
Sub3()#
这里直接贴代码,稍微讲一下坑点:
- 判断所有人都要不起,轮原来的人开牌的情况。
- 开牌的人与出牌的人逻辑要分开,有很大的不同。
- 三带一、三带二、飞机、大顺都能上炸弹。
- 上一位玩家出的炸弹,下一位玩家得出更大的炸弹。
- 王炸无敌。
代码很长(调了 4 天),400 多行,慢慢食用吧:
#include <bits/stdc++.h>
#define rty printf("Yes\n");
#define RTY printf("YES\n");
#define rtn printf("No\n");
#define RTN printf("NO\n");
#define rep(v,b,e) for(int v=b;v<=e;v++)
#define repq(v,b,e) for(int v=b;v<e;v++)
#define rrep(v,e,b) for(int v=b;v>=e;v--)
#define rrepq(v,e,b) for(int v=b;v>e;v--)
#define stg string
#define vct vector
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
void solve() {
}
#define PLANE 1
#define BOMB 2
#define COUPLE 3
#define TRIPLE_O 4
#define TRIPLE_T 5
#define SINGLE 6
#define DOUBLE_KING 7
#define STRAIGHT 8
struct Straight { int start, length, end; };
struct Plane { int start, times, length, end; };
struct Bomb { int card; };
struct Couple {int card; };
struct Triple {int carda, cardb; };
struct Single { int card; };
struct LastCard {
int type;
Straight straight;
Plane plane;
Bomb bomb;
Couple couple;
Triple triple;
Single single;
};
int n;
stg x, y, z;
int c[52][52];
map<stg, int> _m;
stg _mtmp[52] = {"3","4","5","6","7","8","9","10","J","Q","K","A","2","LJ","BJ"};
bool pk(int x) {
rep(j, 1, 15) {
if (c[x][j]) {
return false;
}
}
return true;
}
main() {
// int t; cin >> t; while (t--) solve();
cin >> n;
rep(i, 1, 15) {
_m[_mtmp[i - 1]] = i;
}
rep(i, 1, n) {
rep(j, 1, 51 / n) {
stg tmp;
cin >> tmp;
c[i][_m[tmp]]++;
}
}
cin >> x >> y >> z;
int ix = _m[x], iy = _m[y], iz = _m[z];
int p;
cin >> p;
int pt = p;
bool tmp = 0;
while (1) {
if (pt == p && tmp) {
c[p][ix]++; c[p][iy]++; c[p][iz]++;
break;
}
int sum = 0;
rep(j, 1, 15) {
sum += j * c[pt][j];
}
if (sum % 3 == 1) {
p = pt;
c[pt][ix]++; c[pt][iy]++; c[pt][iz]++;
break;
}
pt++;
if (pt > n) {
pt = 1;
tmp = 1;
}
}
pt = p;
bool flg = 1;
int lastcp_pt = pt;
LastCard lastcard;
while (1) {
if (pk(lastcp_pt)) {
pt = lastcp_pt;
if (pt == p) {
cout << p;
return 0;
} else {
rep(i, 1, n) {
if (i == p) {
continue;
}
cout << i << ' ';
}
return 0;
}
}
if (flg) {
rep(start, 1, 12) {
rrep(end, start + 1, 12) {
rrep(count_times, 2, 4) {
if ((end - start + 1) * count_times < 6) {
continue;
}
rep(i, start, end) {
if (c[pt][i] < count_times) {
goto next_count_times;
}
}
lastcard.type = PLANE;
lastcard.plane.start = start;
lastcard.plane.times = count_times;
lastcard.plane.length = end - start + 1;
lastcard.plane.end = end;
rep(i, start, end) {
c[pt][i] -= count_times;
}
goto lastcp;
next_count_times:;
}
}
}
rep(start, 1, 12) {
rrep(end, start + 1, 12) {
if (end - start + 1 < 6) {
continue;
}
rep(i, start, end) {
if (!c[pt][i]) {
goto next_beginning;
}
}
rep(i, start, end) {
c[pt][i]--;
}
lastcard.type = STRAIGHT;
lastcard.straight.start = start;
lastcard.straight.end = end;
lastcard.straight.length = end - start + 1;
goto lastcp;
next_beginning:;
}
}
int three_times_card = 0;
rep(i, 1, 13) {
if (c[pt][i] >= 3) {
c[pt][i] -= 3;
three_times_card = i;
break;
}
}
if (three_times_card) {
lastcard.triple.carda = three_times_card;
rep(i, 1, 13) {
if (c[pt][i] >= 2 && pt != three_times_card) {
lastcard.type = TRIPLE_T;
lastcard.triple.cardb = i;
c[pt][i] -= 2;
goto lastcp;
}
}
rep(i, 1, 13) {
if (c[pt][i]) {
if (pt == three_times_card) {
if (c[pt][i] < 4) {
continue;
}
}
lastcard.type = TRIPLE_O;
lastcard.triple.cardb = i;
c[pt][i]--;
goto lastcp;
}
}
}
rep(i, 1, 13) {
if (c[pt][i] >= 2) {
lastcard.type = COUPLE;
lastcard.couple.card = i;
c[pt][i] -= 2;
goto lastcp;
}
}
rep(i, 1, 15) {
if (c[pt][i]) {
lastcard.type = SINGLE;
lastcard.single.card = i;
c[pt][i]--;
goto lastcp;
}
}
} else {
if (pt == lastcp_pt) {
flg = 1;
continue;
}
if (lastcard.type == SINGLE) {
rep(i, lastcard.single.card + 1, 15) {
if (c[pt][i]) {
c[pt][i]--;
lastcard.single.card = i;
lastcp_pt = pt;
goto lastcp;
}
}
}
if (lastcard.type == COUPLE) {
rep(i, lastcard.couple.card + 1, 13) {
if (c[pt][i] >= 2) {
c[pt][i] -= 2;
lastcp_pt = pt;
lastcard.couple.card = i;
goto lastcp;
}
}
}
int three_times_card = 0;
rep(i, lastcard.triple.carda + 1, 13) {
if (c[pt][i] >= 3) {
three_times_card = i;
break;
}
}
if (lastcard.type == TRIPLE_T) {
int two_times_card = 0;
rep(i, 1, 13) {
if (i == three_times_card) continue;
if (c[pt][i] >= 2) {
two_times_card = i;
break;
}
}
if (three_times_card && two_times_card) {
c[pt][three_times_card] -= 3;
c[pt][two_times_card] -= 2;
lastcard.triple.cardb = two_times_card;
lastcard.triple.carda = three_times_card;
lastcp_pt = pt;
goto lastcp;
}
rep(i, 1, 13) {
if (c[pt][i] == 4) {
c[pt][i] -= 4;
lastcard.type = BOMB;
lastcard.bomb.card = i;
lastcp_pt = pt;
goto lastcp;
}
}
if (c[pt][14] && c[pt][15]) {
c[pt][14]--;
c[pt][15]--;
lastcard.type = DOUBLE_KING;
lastcp_pt = pt;
}
}
if (lastcard.type == TRIPLE_O) {
if (!three_times_card) continue;
rep(i, 1, 13) {
if (i == three_times_card) {
if (c[pt][i] < 4) continue;
}
if (c[pt][i]) {
c[pt][i]--;
lastcp_pt = pt;
c[pt][three_times_card] -= 3;
lastcard.triple.cardb = i;
goto lastcp;
}
rep(i, 1, 13) {
if (c[pt][i] == 4) {
c[pt][i] -= 4;
lastcard.type = BOMB;
lastcard.bomb.card = i;
lastcp_pt = pt;
goto lastcp;
}
}
if (c[pt][14] && c[pt][15]) {
c[pt][14]--;
c[pt][15]--;
lastcard.type = DOUBLE_KING;
lastcp_pt = pt;
goto lastcp;
}
}
}
if (lastcard.type == BOMB) {
rep(i, lastcard.bomb.card + 1, 13) {
if (c[pt][i] == 4) {
c[pt][i] -= 4;
lastcard.type = BOMB;
lastcp_pt = pt;
goto lastcp;
}
}
if (c[pt][14] && c[pt][15]) {
c[pt][14]--;
c[pt][15]--;
lastcard.type = DOUBLE_KING;
lastcp_pt = pt;
}
}
if (lastcard.type == PLANE) {
rep(i, lastcard.plane.start + 1, 12) {
int e = lastcard.plane.length + i + 1;
rep(k, i, e) {
if (c[pt][k] < lastcard.plane.times) {
goto repp;
}
}
rep(k, i, e) {
c[pt][k] -= lastcard.plane.times;
}
lastcp_pt = pt;
lastcard.plane.start = i;
lastcard.plane.end = e;
goto lastcp;
repp:;
}
rep(i, 1, 13) {
if (c[pt][i] == 4) {
c[pt][i] -= 4;
lastcard.type = BOMB;
lastcard.bomb.card = i;
lastcp_pt = pt;
goto lastcp;
}
}
if (c[pt][14] && c[pt][15]) {
c[pt][14]--;
c[pt][15]--;
lastcard.type = DOUBLE_KING;
lastcp_pt = pt;
goto lastcp;
}
}
if (lastcard.type == STRAIGHT) {
rep(i, lastcard.straight.start + 1, 12) {
int e = lastcard.straight.length + i;
rep(k, i, e) {
if (c[pt][k] < 1) {
goto nerepp;
}
}
rep(k, i, e) {
c[pt][k]--;
}
lastcp_pt = pt;
lastcard.straight.start = i;
lastcard.straight.end = e;
goto lastcp;
nerepp:;
}
rep(i, 1, 13) {
if (c[pt][i] == 4) {
c[pt][i] -= 4;
lastcard.type = BOMB;
lastcard.bomb.card = i;
lastcp_pt = pt;
goto lastcp;
}
}
if (c[pt][14] && c[pt][15]) {
c[pt][14]--;
c[pt][15]--;
lastcard.type = DOUBLE_KING;
lastcp_pt = pt;
goto lastcp;
}
}
}
lastcp:;
if (flg) flg = 0;
pt++;
if (pt > n) pt = 1;
}
return 0;
}
作者:2044-space-elevator
出处:https://www.cnblogs.com/2044-space-elevator/articles/18388518
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!