SX【2020.01.09】NOIP提高组模拟赛(day1)
【2020.01.09】NOIP提高组模拟赛(day1)
这次考得不理想,只做了前两题,后两题没时间做,说明做题速度偏慢。
source : 100 + 20 + 0 + 0 = 120 rank7
十分不友好。
算了,进入正题
传送门:[USACO17JAN]Cow Dance Show奶牛舞蹈
分析
一道清新的水题,很容易想到二分答案,易证满足单调性。
然后考虑可以接受的
根据时间维护一个小根堆,取堆首时判断。
然后——切了
代码略
传送门:[USACO17JAN]Hoof, Paper, Scissor蹄子剪刀…
一道本应该是没多难的 ,然而考场时漏考虑一种转移,直接炸到 分。
根据题意,容易想到设状态 表示到第 回合,有改变 次的机会,且当前出 (H/S/P,设为 )
考虑转移:
设 , 表示不同于 的另外两个手势, 表示手势 能赢手势 , 表示当前 的手势 则有:
代码
#include<cstdio> #include<iostream> using namespace std; const int N = 1e5; int n , k , a[N + 5] , f[N + 5][25][4] , ans = 0 , p , q; char ch; int data[4][4]; int main() { // freopen("hps.in" , "r" , stdin); // freopen("hps.out" , "w" , stdout); scanf("%d%d" , &n , &k); for(register int i = 1; i <= n; i++) { ch = getchar(); while (ch != 'H' && ch != 'P' && ch != 'S') ch = getchar(); if (ch == 'H') a[i] = 1; else if (ch == 'P') a[i] = 2; else if (ch == 'S') a[i] = 3; } data[1][3] = data[2][1] = data[3][2] = 1; for(register int i = 1; i <= n; i++) for(register int j = 1; j <= 3; j++) f[i][0][j] = f[i - 1][0][j] + data[j][a[i]]; for(register int i = 1; i <= n; i++) for(register int j = 1; j <= k; j++) for(register int l = 1; l <= 3; l++) { if (l == 1) p = 2 , q = 3; else if (l == 2) p = 1 , q = 3; else if (l == 3) p = 1 , q = 2; f[i][j][l] = max(f[i - 1][j][l] + data[l][a[i]], max(f[i - 1][j - 1][p] + data[l][a[i]] , f[i - 1][j - 1][q] + data[l][a[i]])); } for(register int i = 0; i <= k; i++) for(register int j = 1; j <= 3; j++) ans = max(f[n][i][j] , ans); printf("%d" , ans); }
没了······
传送门:[USACO17JAN]Cow Navigation奶牛导航
一道不是很难但码量大,细节多的题
:用 模拟做
详细解析如下:
先转化:因为读入的地图缘故,所以我们设起点 ,终点
有两头奶牛,分别在 处面向两个方向
且要注意:到终点的奶牛无视任何新增命令,不管另一头牛怎样,他都不动;若当前指令有一头牛会越界,也不动。(详细认真看题目)
设 表示牛一到达 面向 ,牛二到达 面向 时的指令最短长度
因指令每个对答案的贡献都是 ,所以可以用 来做最短路 ,边扩展边更新
但实际上可以优化空间,那就是弄掉 那一维
很好想,因为两头牛接受同一个指令,他们的方向是相对的,知道其中一头,就能知道另一头,取决于一开始的朝向
代码
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N = 20; int n , map[N + 5][N + 5] , head , tail , ans = 1e5; int f[N + 5][N + 5][4][N + 5][N + 5][4] , vis[N + 5][N + 5][4][N + 5][N + 5][4]; int fx[4][2] = { -1 , 0 , 0 , 1 , 1 , 0 , 0 , -1 }; char ch; struct node{ int x1 , y1 , d1 , x2 , y2 , d2; }q[N * N * N * N * 16 + 10]; inline bool check(int x , int y , int xx , int yy) { return (x <= 0 || y <= 0 || x > n || y > n || map[x][y] == 1 || (xx == 1 && yy == n)); } int main() { // freopen("cow.in" , "r" , stdin); // freopen("cow.out" , "w" , stdout); scanf("%d" , &n); for(register int i = 1; i <= n; i++) for(register int j = 1; j <= n; j++) { while (ch != 'E' && ch != 'H') ch = getchar(); if (ch == 'H') map[i][j] = 1; ch = getchar(); } q[++tail] = (node){n , 1 , 0 , n , 1 , 1}; memset(f , 0x3f , sizeof(f)); f[n][1][0][n][1][1] = 0; vis[n][1][0][n][1][1] = 1; while (head < tail) { struct node now = q[++head]; int x1 , y1 , d1 , x2 , y2 , d2; d1 = now.d1 , d2 = now.d2; x1 = now.x1 + fx[d1][0] , y1 = now.y1 + fx[d1][1]; if (check(x1 , y1 , now.x1 , now.y1)) x1 = now.x1 , y1 = now.y1; x2 = now.x2 + fx[d2][0] , y2 = now.y2 + fx[d2][1]; if (check(x2 , y2 , now.x2 , now.y2)) x2 = now.x2 , y2 = now.y2; if (f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1 < f[x1][y1][d1][x2][y2][d2] && vis[x1][y1][d1][x2][y2][d2] == 0) { q[++tail] = (node){x1 , y1 , d1 , x2 , y2 , d2}; f[x1][y1][d1][x2][y2][d2] = f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1; vis[x1][y1][d1][x2][y2][d2] = 1; } d1 = (now.d1 + 1) % 4 , d2 = (now.d2 + 1) % 4; x1 = now.x1 , y1 = now.y1 , x2 = now.x2 , y2 = now.y2; if (f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1 < f[x1][y1][d1][x2][y2][d2] && vis[x1][y1][d1][x2][y2][d2] == 0) { q[++tail] = (node){x1 , y1 , d1 , x2 , y2 , d2}; f[x1][y1][d1][x2][y2][d2] = f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1; vis[x1][y1][d1][x2][y2][d2] = 1; } d1 = (now.d1 + 3) % 4 , d2 = (now.d2 + 3) % 4; x1 = now.x1 , y1 = now.y1 , x2 = now.x2 , y2 = now.y2; if (f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1 < f[x1][y1][d1][x2][y2][d2] && vis[x1][y1][d1][x2][y2][d2] == 0) { q[++tail] = (node){x1 , y1 , d1 , x2 , y2 , d2}; f[x1][y1][d1][x2][y2][d2] = f[now.x1][now.y1][now.d1][now.x2][now.y2][now.d2] + 1; vis[x1][y1][d1][x2][y2][d2] = 1; } } for(register int i = 0; i < 4; i++) for(register int j = 0; j < 4; j++) ans = min(ans , f[1][n][i][1][n][j]); printf("%d" , ans); }
传送门:[USACO17JAN]Subsequence Reversal序列反转
解析如下:
似乎无从下手的题,其实是个很套路的区间
根据数值只有 的特性,我们可以用神奇的操作弄掉所谓的翻转
废话不多说,且看
设 表示区间 ,数值取值范围 时的最长子序列长度
然后区间 套路转移,但两个区间是套在一起转移的
代码
#include<cstdio> #include<iostream> using namespace std; const int N = 50; int n , f[N + 5][N + 5][N + 5][N + 5] , a[N + 5] , Mx; int main() { // freopen("reversal.in" , "r" , stdin); // freopen("reversal.out" , "w" , stdout); scanf("%d" , &n); for(register int i = 1; i <= n; i++) { scanf("%d" , &a[i]); for(register int down = 1; down <= a[i]; down++) for(register int up = a[i]; up <= 50; up++) f[i][i][down][up] = 1; } for(register int len1 = 2; len1 <= n; len1++) for(register int i = 1; i <= n - len1 + 1; i++) { register int j = i + len1 - 1; for(register int len2 = 2; len2 <= 50; len2++) for(register int down = 1; down <= 51 - len2; down++) { register int up = down + len2 - 1 , Mx; Mx = max(f[i][j][down + 1][up] , f[i][j][down][up - 1]); Mx = max(f[i + 1][j][down][up] + (a[i] == down) , Mx); Mx = max(f[i][j - 1][down][up] + (a[j] == up) , Mx); Mx = max(f[i + 1][j - 1][down][up] + (a[j] == down) + (a[i] == up) , Mx); f[i][j][down][up] = Mx; } } printf("%d" , f[1][n][1][50]); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具