【题解】gym103495 (2021 JSCPC)
A. Spring Couplets
就是判断是否满足一下条件:
- 对联对位上平下仄、上仄下平
- 第一句对联的最后一个是仄
模拟即可。
code:
#include<bits/stdc++.h> using namespace std; const int NN = 30; int T,n; int a[NN],b[NN]; inline int read(){ register char c = getchar(); register int res = 0; while(!isdigit(c)) c = getchar(); while(isdigit(c)) res = res * 10 + c - '0',c = getchar(); return res; } void solve(){ n = read(); for(int i = 1; i <= n; ++i) a[i] = read(); for(int i = 1; i <= n; ++i) b[i] = read(); for(int i = 1; i <= n; ++i) if((a[i] <= 2 && b[i] <= 2) || (a[i] >= 3 && b[i] >= 3)) return puts("NO"),void(0); if(a[n] <= 2) return puts("NO"),void(0); else return puts("YES"),void(0); } int main(){ T = read(); while(T--){ solve(); } }
B. Among Us
这道题我们考虑
我们考虑有两个杀手,我们可以对每个杀手分别求一遍,然后合并起来。
对于一个杀手,我们设
如何转移?我们考虑使用
转移分成两种:
- 待在一个房间干掉下一个人
- 去其他房间
code:
还没有~~~
C. Magical Rearrangement
这道题显然从高位到低位,从小到大贪心即可。
当然需要特判只有一个
code:
#include<bits/stdc++.h> using namespace std; const int NN = 1e5 + 8; int T; int a[NN]; inline int read(){ register char c = getchar(); register int res = 0; while(!isdigit(c)) c = getchar(); while(isdigit(c)) res = res * 10 + c - '0',c = getchar(); return res; } void solve(){ int sum = 0; for(int i = 0; i <= 9; ++i) sum += (a[i] = read()); if(sum == 1 && a[0] == 1){ return puts("0"),void(0); } for(int i = 0; i <= 9; ++i){ if((sum + (i != 0)) / 2 < a[i]) return puts("-1"),void(0); } for(int i = 1,pre = 0; i <= sum; ++i){ int x = -1; for(int j = 0; j <= 9; ++j){ if(pre == j) continue; if((sum - i + 2) == 2 * a[j]){x = j;break;} } if(x == -1){ for(int j = 0; j <= 9; ++j){ if(pre == j) continue; if(a[j] != 0){x = j;break;} } } printf("%d",x); --a[x]; pre = x; } puts(""); } int main(){ T = read(); while(T--){ solve(); } }
D. Pattern Lock
我们考虑比较正常的想法就是我们可以发现以锯齿状的方式可以一次性将一个

我们考虑怎么扩展到

可以发现上图都是小于
现在我们就可以构造所有
我们发现,挖去一个

然后上图中的浅绿色的线是拿来衔接矩阵之间的线,红色是锯齿形解决 偶
至于左上角的
code:
#include<bits/stdc++.h> using namespace std; int n,m; int addx,addy; bool tag; void print(int x,int y){ x += addx;y += addy; if(tag) printf("%d %d\n",y,x); else printf("%d %d\n",x,y); } void solve1(int n,int m,int op = 1){ if(m == 2){ for(int i = 1; i <= n; ++i){ print(i,1); print(i,2); } return; } for(int i = 1; i <= n / 2; ++i){ if((i & 1) == op){ print(i*2-1,m); print(i*2,1); print(i*2-1,1); for(int j = 2; j <= m-1; ++j){ print(i*2,j); print(i*2-1,j); } print(i*2,m); } else{ print(i*2-1,1); print(i*2,m); print(i*2-1,m); for(int j = m-1; j >= 2; --j){ print(i*2,j); print(i*2-1,j); } print(i*2,1); } } } void solve2(int n,int m){ if(n > m) swap(n,m),tag ^= 1; if(((m-3) % 4) == 0){ print(1,1);print(2,3);print(3,1); print(3,2);print(2,1);print(1,3); print(2,2);print(1,2);print(3,3); addx = 3;addy = 0; tag ^= 1; solve1(m-3,3,0); tag ^= 1; addx = addy = 0; } else{ print(3,1);print(2,3);print(1,1); print(1,2);print(2,1);print(3,3); print(2,2);print(3,2);print(1,3); addx = 3;addy = 0; tag ^= 1; solve1(m-3,3,1); tag ^= 1; addx = addy = 0; } addx = 3,addy = 0; solve1(n-3,m,0); } int main(){ scanf("%d%d",&n,&m); if(m % 2 == 0) swap(n,m),tag = 1; if(n % 2 == 0){ solve1(n,m); } else{ solve2(n,m); } }
E. Stone Ocean
我们首先把期望转化为 权值和
这道题我们考虑还是状态压缩,设
因为当
至于代码实现可以使用队列将每一层可以到达的状态找出来,按层转移。
code:
还没有QAQ~~~
F. Jumping Monkey II
我们考虑,只有子树内的
我们考虑如何去求一个点父亲方向的 淀粉质
,我们可以将一个父亲方向的路径按分治中心分成
然后对每个分治中心,维护其每棵子树的最长下降子序列的 DP
数组,将这些 DP
数组合并到分治中心,再贡献给每棵子树的每个结点
时间复杂度
code:
还没有QAQ~~~
G. Five Phases
我们考虑生成函数,由题可以得到答案是下面这个式子:
然后我们考虑化简之后可以变成:
然后我们设
答案就是
code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int NN = 1e5 + 8,MOD = 998244353; ll fac[NN],inv[NN]; inline int read(){ register char c = getchar(); register int res = 0,flag = 1; while(!isdigit(c)) flag = c == '-' ? -1 : flag,c = getchar(); while(isdigit(c)) res = res * 10 + c - '0', c = getchar(); return res*flag; } inline ll ksm(ll x,ll k){ ll res = 1; while(k){ if(k&1) res = res * x % MOD; x = x * x % MOD; k >>= 1; } return res; } void init(){ fac[0] = 1; for(int i = 1; i < NN; ++i) fac[i] = fac[i-1] * i % MOD; inv[NN-1] = ksm(fac[NN-1],MOD - 2); for(int i = NN-1; i >= 1; --i) inv[i-1] = inv[i] * i % MOD; } inline ll binom(ll n,ll m){ if(m % 2 != 0) return 0; else m /= 2; if(m > n || n < 0 || m < 0) return 0; return fac[n] * inv[m] % MOD * inv[n-m] % MOD; } void solve(){ ll a = read(),b = read(),c = read(),d = read(),e = read(),k = read(); ll o,p,q,r,s; o = (b-c+d-e+a+k); p = (c-d+e-a+b+k); q = (d-e+a-b+c+k); r = (e-a+b-c+d+k); s = (a-b+c-d+e+k); printf("%lld\n", binom(k,o) * binom(k,p) % MOD * binom(k,q) % MOD * binom(k,r) % MOD * binom(k,s) % MOD); } int main(){ init(); int T = read(); while(T--){ solve(); } }
H. Reverse the String
你考虑字典序最小的字符串显然就是排序之后的字符串。
我们考虑翻转字符串的左端点应该在哪里,显然就是原字符串和排序之后的字符串的第一个不同的位置就是翻转的左端点。
我们现在需要找到最优的翻转的右端点,我们考虑
我们考虑我们可以加速这个过程,我们考虑如何快速比较两个字符串的大小,显然可以通过 二分+Hash
解决这个问题。
code:
还没有QAQ~~~
I. Fake Walsh Transform
考虑这道题,我们发现
当然当
J. Anti-merge
最后应该到达的状态显然是:
- 对于任意单元格内容,将不添加标签看成
号标签。对于一个单元格,由单元格内容和单元格标签组成的 pair 对应该与它四连通的所有单元格互不相同。
考虑黑白棋盘染色,可知最少所用颜色数不超过
对于方案的求解,可以考虑使用 BFS,从每个位置开始对 pair 相同的单元格区域进行这种黑白染色,取黑白颜色数较少的颜色填充标签即可。
K. Longest Continuous 1
我们可以进行 打表
发现每个长度第一次出现的位置都是
我们考虑如何证明:
我们发现连续的
只能由两个数字构成,因为两个数字一定是一奇一偶
- 若前奇后偶,那么可以发现最早的一定是上面的情况
- 若前偶后奇,那么最优一定会是这样:
+ 我们会发现它一定不能超过一个 串的长度,显然是不优的
我们考虑设
然后我们就可以预处理出 爆扫
或者 二分答案
即可。
L. Tree Game
我们首先需要判断无解,这是很好判断的,就是忽略可以填任意数的位置,模拟一遍即可
然后我们设
为什么是
我们考虑当最后的操作完之后,我们的每个
因为前面已经判过了无解,所以说确定的数的位置是确定的,只有
然后这道题就完了
最后这套题就完了~
有一些题目的代码有时间再补,没时间就咕咕咕~~~
本文来自博客园,作者:ricky_lin,转载请注明原文链接:https://www.cnblogs.com/rickylin/p/17957316/gym103495
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步