上海市中小学生人工智能算法设计复赛 - 高中组 (S) 比赛游记
比赛链接(已结束):戳我打开。
比赛时间:15:30~19:00。
估了好久的补偿赛,感觉题目质量还行吧。
第一题:
看到之后居然感觉无从下手?
有了最小的数据范围
打算写之前随便特判了几组数据,然后发现有人已经
想写的念头就没了,接着发现
然后还是没什么思路,写了个动态规划。
感觉写出来之后是否
结果发现真的出来了,直接枚举花多长时间做题,剩下的时间
但是花这么多时间
还是需要一个动态规划,
状态转移方程为
二分就行了,时间复杂度为
考试结束后听同学说应该把分数作为维度算,反正过了就行了呗(\doge。
考场代码:
#include <cstring> #include <iostream> #include <algorithm> using namespace std; int n, m, _t, ans = 0x3f3f3f3f; int f[10000005], dp[505][505];//f[i]:花费i时间做题所能得到的最大分数 //dp[i][j]:前i个人中Hackj个人所需要花费的最少时间 struct problem { int t, s; }a[110]; struct people { int t, s; }b[510]; bool cmp (people p1, people p2) { return p1.s > p2.s || p1.s == p2.s && p1.t < p2.t; } int main () { scanf ("%d%d%d", &n, &m, &_t); for (int i = 1; i <= n; i ++) scanf ("%d%d", &a[i].t, &a[i].s); for (int i = 1; i <= m; i ++) scanf ("%d%d", &b[i].t, &b[i].s); sort (b + 1, b + m + 1, cmp); for (int i = 1; i <= n; i ++) for (int j = _t; j >= 0; j --) if (j >= a[i].t) f[j] = max(f[j], f[j - a[i].t] + a[i].s); memset (dp, 0x3f, sizeof dp); dp[1][0] = 0; dp[1][1] = b[1].t; for (int i = 2; i <= m; i ++) { dp[i][0] = 0; for (int j = 1; j <= i; j ++) dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1] + b[i].t); } for (int i = 0; i <= _t; i ++) {//枚举花费多长的时间做题 int score = f[i], rank;//所能够得到的分数 int l = 1, r = m, mid;//二分查找该分数的排名 while (l <= r) { mid = l + r >> 1; if (b[mid].s > score) l = mid + 1; else r = mid - 1; } rank = r + 1;//当前这个人的排名 int t_ = _t - i;//剩下的可以Hack别人的时间 l = 1; r = rank - 1;//二分查找最多能Hack前rank名中的几名 while (l <= r) { mid = l + r >> 1; if (dp[rank - 1][mid] > t_) r = mid - 1;//需要更多的时间,无法Hack else l = mid + 1;//可以Hack,扩大左边界 } ans = min (ans, rank - r);//可以Hack r名,排名由rank名变为rank-r名 } printf ("%d", ans); return 0; }
第二题:
方格路径加强版,考前没复习,打了
状态转移方程:
如果有障碍物,
后来看到有些人拿了
仔细一看数据范围有个
写了个矩阵乘法
考场
#include <iostream> using namespace std; const int mod = 1e9 + 7; long long n, m; long long x1, y1, x2, y2; long long f[7][100005], ans[7][7], pre[7][7] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1}; bool a[7][100010]; void time (long long a[7][7], long long b[7][7]) { long long c[7][7] = {0}; for (int i = 1; i <= 6; i ++) for (int k = 1; k <= 6; k ++) for (int j = 1; j <= 6; j ++) c[i][k] = (c[i][k] + a[i][j] * b[j][k] % mod) % mod; for (int i = 1; i <= 6; i ++) for (int j = 1; j <= 6; j ++) a[i][j] = c[i][j]; } int main () { cin >> n >> m; if (m == 0) { if (n == 1) { cout << 6; return 0; } else if (n == 2) { cout << 16; return 0; } for (int i = 1; i <= 6; i ++) for (int j = 1; j <= 6; j ++) ans[i][j] = 1; m = n - 2; while (m) { if (m & 1) time (ans, pre); time (pre, pre); m >>= 1; } cout << (ans[1][1] + ans[1][2] + ans[2][1] + ans[2][2] + ans[2][3] + ans[3][2] + ans[3][3] + ans[3][4] + ans[4][3] + ans[4][4] + ans[4][5] + ans[5][4] + ans[5][5] + ans[5][6] + ans[6][5] + ans[6][6]) % mod; } else { for (int i = 1; i <= m; i ++) { cin >> x1 >> y1 >> x2 >> y2; for (long long j = x1; j <= x2; j ++) for (long long k = y1; k <= y2; k ++) a[j][k] = true; } f[1][1] = f[2][1] = f[3][1] = f[4][1] = f[5][1] = f[6][1] = 1; for (int j = 2; j <= n; j ++) { if (! a[1][j]) f[1][j] = (f[1][j - 1] + f[2][j - 1]) % 1000000007; for (int i = 2; i <= 5; i ++) if (! a[i][j]) f[i][j] = (f[i - 1][j - 1] + f[i][j - 1] + f[i + 1][j - 1]) % 1000000007; if (! a[6][j]) f[6][j] = (f[5][j - 1] + f[6][j - 1]) % 1000000007; } cout << ( ( (f[1][n] + f[2][n]) % 1000000007 + (f[3][n] + f[4][n]) % 1000000007) % 1000000007 + (f[5][n] + f[6][n]) % 1000000007) % 1000000007; } return 0; }
第三题:
毒瘤题,考试的时候以为是结论题,写了不对。
以为是二分题,写一大会儿不出。
然后写
发现
就加了一个”随机性剪枝“,反正合法方案肯定很多,如果
有一个点正好
第四题:
我打
于是打了
然后打出来就
总共:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)