@Dmaxiya
2020-12-15T15:27:27.000000Z
字数 10126
阅读 1182
暑期集训
链接:2018 Multi-University Training Contest 4
过题数:3
排名:333/802
成员:官展鹏,冯彦博,孙昊哲
总共有 个苹果,编号分别为 到 ,问最多能摘到 个苹果的总方案数。
第一行包含一个整数 ,接下去有 组数据,每组数据包含两个整数 和 。
对每组数据,输出答案对 取模的结果。
| 输入 |
|---|
| 2 5 2 1000 500 |
| 输出 |
| 16 924129523 |
个苹果最多能摘到 个的方案数为 ,由于这个公式的计算是 的,所以 组数据显然超时,考虑离线莫队。
我们定义 ,设 ,则有:
于是将上标 设为左区间 ,下标 设为右区间 ,有以下转移方程:
方程中的每一项都可以 求得,因此总的时间复杂度为 。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <sstream>using namespace std;#define LL long longconst int maxn = 100000 + 100;const int MOD = 1000000007;struct Node {int l, r;int Index;};int sq;bool operator<(const Node &a, const Node &b) {return a.r / sq == b.r / sq? a.l < b.l: a.r < b.r;}int T, n, m, l, r, Max;int ans[maxn];Node node[maxn];int inv[maxn], pro[maxn], invpro[maxn];void Init() {inv[1] = 1;for(int i = 2; i < maxn; ++i) {inv[i] = (LL)(MOD - MOD / i) * inv[MOD % i] % MOD;}pro[0] = invpro[0] = 1;for(int i = 1; i < maxn; ++i) {pro[i] = (LL)pro[i - 1] * i % MOD;invpro[i] = (LL)invpro[i - 1] * inv[i] % MOD;}}int get_C(int n, int m) {if(n < m) {return 0;}return (LL)pro[n] * invpro[m] % MOD * invpro[n - m] % MOD;}int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);Max = 0;Init();scanf("%d", &T);for(int i = 0; i < T; ++i) {scanf("%d%d", &node[i].r, &node[i].l);node[i].Index = i;Max = max(Max, node[i].r);}sq = sqrt(Max);sort(node, node + T);l = 1;r = 0;LL tmp = 1;LL ttmp;for(int i = 0; i < T; ++i) {while(r < node[i].r) {ttmp = tmp + tmp;if(ttmp >= MOD) {ttmp -= MOD;}tmp = ttmp - get_C(r, l);if(tmp < 0) {tmp += MOD;}++r;}while(l > node[i].l) {tmp = tmp - get_C(r, l);if(tmp < 0) {tmp += MOD;}--l;}while(r > node[i].r) {ttmp = tmp + get_C(r - 1, l);if(ttmp >= MOD) {ttmp -= MOD;}tmp = (ttmp * inv[2]) % MOD;--r;}while(l < node[i].l) {tmp = tmp + get_C(r, l + 1);if(tmp >= MOD) {tmp -= MOD;}++l;}ans[node[i].Index] = tmp;}for(int i = 0; i < T; ++i) {printf("%d\n", ans[i]);}return 0;}
一个班上有 个学生参加考试,试卷上总共有 道题,每道题有 个正确选项和 个错误选项,每个学生每道题只能从 个选项中选择一个选项作为答案,每个学生都不知道正确答案,但是这个教室内的学生在考试期间可以相互讨论,且他们十分团结,他们想让班上的最高分的做对的题数最多,问他们在采取最优策略下,能够做对的最多的题数。
第一行为一个整数 ,接下去有 组数据,每组数据第一行为两个整数 ,接下去 行每行两个整数 。
输出最高分能够做对的最多的题数。
| 输入 |
|---|
| 2 3 5 1 3 1 3 1 3 5 50 1 1 1 3 1 2 1 3 1 5 |
| 输出 |
| 1 3 |
个人认为这题应该加一个“最高分至少能够做对的题数”,即在他们所有人运气都最坏的情况下,能够做对的题数的最大值,最优策略就是让所有人的答案填法按照 进制一个一个地填上去,如果能够达到第 位,则说明第 位以下的所有情况都已经填上去,也就至少能够保证做对 道题,为了让位数增长最快,应该让 值小的作为低位。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <sstream>using namespace std;#define LL long longconst int maxn = 100 + 100;struct Node {int a, b;};bool operator<(const Node &a, const Node &b) {return a.b < b.b;}int T, n, m, ans;Node node[maxn];int num[maxn];int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);scanf("%d", &T);while(T--) {ans = 0;scanf("%d%d", &n, &m);for(int i = 0; i < n; ++i) {scanf("%d%d", &node[i].a, &node[i].b);}sort(node, node + n);for(int i = 0; i < n; ++i) {if(m > node[i].b) {++ans;}m /= (node[i].b + 1);}printf("%d\n", ans);}return 0;}
给定一个长度为 的数组 ,用以下代码生成一个无穷大矩阵:
int cursor = 0;for (int i = 0; ; ++i) {for (int j = 0; j <= i; ++j) {M[j][i - j] = A[cursor];cursor = (cursor + 1) % L;}}
有 次询问,每次询问为从第 行 列到第 行 列的子矩阵中数字的和。
第一行为一个整数 ,接下有 组数据,每组数据第一行为一个整数 ,第二行为 个整数 ,第三行为一个整数 ,接下去 行每行四个整数 。
对于每次询问,输出结果。
| 输入 |
|---|
| 1 3 1 10 100 5 3 3 3 3 2 3 3 3 2 3 5 8 5 1 10 10 9 99 999 1000 |
| 输出 |
| 1 101 1068 2238 33076541 |
打表可以发现矩阵的循环节为 ,因此可以只打出 的矩阵,就可以通过循环节求出所有矩阵的值,设 为无穷大矩阵前 行 列的和,则所求子矩阵的和为
注意 取得 的情况。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <sstream>using namespace std;#define LL long longconst int maxn = 100 + 100;int T, n, q;int a[maxn];LL num[maxn][maxn];LL Sum(int x, int y) {if(x < 0 || y < 0) {return 0;}int nn = n << 1;LL ret = num[nn - 1][nn - 1] * ((x + 1) / nn) * ((y + 1) / nn);int xx = x % nn;int yy = y % nn;if(xx != nn - 1) {ret += num[xx][nn - 1] * ((y + 1) / nn);}if(yy != nn - 1) {ret += num[nn - 1][yy] * ((x + 1) / nn);}if(xx != nn - 1 && yy != nn - 1) {ret += num[xx][yy];}return ret;}int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);scanf("%d", &T);while(T--) {scanf("%d", &n);for(int i = 0; i < n; ++i) {scanf("%d", &a[i]);}int Index = 0;for(int i = 0; i < maxn; ++i) {for(int j = 0; j <= i; ++j) {num[j][i - j] = a[Index];Index = (Index + 1) % n;}}for(int i = 0; i < maxn; ++i) {for(int j = 0; j < maxn; ++j) {if(i != 0) {num[i][j] += num[i - 1][j];}if(j != 0) {num[i][j] += num[i][j - 1];}if(i != 0 && j != 0) {num[i][j] -= num[i - 1][j - 1];}}}scanf("%d", &q);int x1, x2, y1, y2;while(q--) {scanf("%d%d%d%d", &x1, &y1, &x2, &y2);LL ans = Sum(x2, y2) + Sum(x1 - 1, y1 - 1);ans -= Sum(x2, y1 - 1) + Sum(x1 - 1, y2);printf("%I64d\n", ans);}}return 0;}
有一个 的数独,其中的每一行、每一列、每一 的方格内都不重复地包含 到 的每一个十六进制数, 已经完成了一个数独,但是被 逆时针旋转了其中的某几个 的方格,给出旋转后的方格,问最少需要几步才能从原数独逆时针旋转到当前状态。
第一行为一个整数 ,接下来有 组数据,每组数据为一个 的字符矩阵,矩阵中只包含 到 以及 到 这 种字符,表示最终的数独状态。
输出一个非负整数,表示最少需要的操作次数。
| 输入 |
|---|
1681D5A0C9FDBB2F70A734B62E167D9E55C9B73EF3C208410F24ED18948A5CA6339FAED5616400B74D120C4B7CA3DEF387EC829A085BE6D51B56438F129F79C2A5C7FBC4E3D08719FAE8B1673BF42A58D60D3AF25619C30BE294190D8EA57264CC7D1B35606835EABAF52A1E019BE43068B36DC78D425F7C9E409492FC7FA18D2 |
| 输出 |
| 5 |
| 提示 |
原数独按照如下方式旋转可以得到所输入的数独:![]() |
将每个 格子顺时针旋转,每次旋转检查是否与当前格子左上方的所有格子冲突,若冲突则剪枝,否则继续往下搜索,“由于数独限制较强,剪枝效果良好。”
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <sstream>using namespace std;#define LL long longconst int maxn = 100;int T, cnt, ans;int num[maxn][maxn], Copy[maxn][maxn];char str[maxn][maxn];int vis[20];void Print() {for(int i = 0; i < 16; ++i) {for(int j = 0; j < 16; ++j) {printf("%3d", num[i][j]);}printf("\n");}}void rot(int x, int y) {for(int i = 0; i < 4; ++i) {for(int j = 0; j < 4; ++j) {Copy[x + j][y + 3 - i] = num[x + i][y + j];}}for(int i = 0; i < 4; ++i) {for(int j = 0; j < 4; ++j) {num[x + i][y + j] = Copy[x + i][y + j];}}}bool Check(int x, int y) {for(int i = x; i < x + 4; ++i) {++cnt;for(int j = 0; j < y + 4; ++j) {if(vis[num[i][j]] == cnt) {return false;}vis[num[i][j]] = cnt;}}for(int j = y; j < y + 4; ++j) {++cnt;for(int i = 0; i < x + 4; ++i) {if(vis[num[i][j]] == cnt) {return false;}vis[num[i][j]] = cnt;}}return true;}void dfs(int depth, int step) {if(depth == 16) {ans = min(ans, step);return ;}int x = depth / 4;int y = depth % 4;for(int i = 0; i < 4; ++i) {if(Check(x * 4, y * 4)) {dfs(depth + 1, step + i);}rot(x * 4, y * 4);}}int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);scanf("%d", &T);while(T--) {for(int i = 0; i < 16; ++i) {scanf("%s", str[i]);for(int j = 0; j < 16; ++j) {if(str[i][j] <= '9') {num[i][j] = str[i][j] - '0';} else {num[i][j] = str[i][j] - 'A' + 10;}}}ans = INT_MAX;dfs(0, 0);printf("%d\n", ans);}return 0;}
给定一个合法表达式的定义(即我们平时认为的合法表达式):表达式中每个数字除 以外其他数字不包含前导零,表达式中只包含加号和乘号,两个数字之间只能包含一个加号或乘号,加号和乘号必须包含在数字之间。给定一个字符串,字符串中只含有字符
0到9、+、*以及?,其中?可以被替换成任意一个字符,如果可以将给出的字符串替换为合法的表达式,则输出替换后的表达式,否则输出 。
第一行为一个整数 ,接下去有 组数据,每组数据为一行字符串 ,字符串中只包含字符
0到9和+、*、?。
如果可以通过替换其中的所有
?成为一个合法的表达式,则输出最终的合法表达式,否则输出 ,若有多解输出任意一个。
| 输入 |
|---|
5?????0+0+0?+*???0+?0?0+0? |
| 输出 |
111110+0+0IMPOSSIBLE10+10IMPOSSIBLE |
首先如果有
?在一个单独的零(零前无字符,或者是加号与乘号)后面,就将?替换为+,否则将?替换为1,替换结束后检查字符串格式是否为一个合法的表达式,如果是则输出字符串,否则输出 。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <sstream>using namespace std;#define LL long longconst int maxn = 500 + 100;int T;char str[maxn];bool single_zero(int Index) {if(str[Index] != '0') {return false;}if(Index == 0 || str[Index - 1] == '+' || str[Index - 1] == '*') {return true;}return false;}bool Check() {int len = strlen(str);if(!isdigit(str[0]) || !isdigit(str[len - 1])) {return false;}int Index = 0;while(Index < len) {if(str[Index] == '0' && isdigit(str[Index + 1])) {return false;}while(Index < len && str[Index] != '+' && str[Index] != '*') {++Index;}++Index;if(Index >= len) {return true;}if(!isdigit(str[Index])) {return false;}}return true;}int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);scanf("%d", &T);while(T--) {scanf("%s", str);for(int i = 0; str[i]; ++i) {if(str[i] == '?') {if(i > 0 && single_zero(i - 1)) {str[i] = '+';} else {str[i] = '1';}}}if(Check()) {printf("%s\n", str);} else {printf("IMPOSSIBLE\n");}}return 0;}
给定 个节点的完全图,每个节点都有一个权值 ,节点 和节点 之间的边权为 ,问从节点 到节点 的最短路径长度。
第一行为一个整数 ,接下来有 组数据,每组数据第一行为一个整数 ,第二行有 个整数 。
输出节点 到节点 的最短路径。
| 输入 |
|---|
| 1 3 1 3 5 |
| 输出 |
| 2 |
从节点 到节点 之间,经历的中间节点越多, 到 的距离越长,最短距离就是从节点 到 的边权。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <climits>#include <cstring>#include <string>#include <vector>#include <list>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <algorithm>#include <sstream>using namespace std;#define LL long longconst int maxn = 100000 + 100;int T, n;int num[maxn];int main() {#ifdef Dmaxiyafreopen("test.txt", "r", stdin);// freopen("out.txt", "w", stdout);#endif // Dmaxiyaios::sync_with_stdio(false);scanf("%d", &T);while(T--) {scanf("%d", &n);for(int i = 1; i <= n; ++i) {scanf("%d", &num[i]);}printf("%d\n", (int)sqrt(abs(num[n] - num[1])));}return 0;}