@Dmaxiya
2020-12-15T23:27:27.000000Z
字数 10126
阅读 958
暑期集训
链接: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 long
const 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 Dmaxiya
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // Dmaxiya
ios::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 long
const 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 Dmaxiya
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // Dmaxiya
ios::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 long
const 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 Dmaxiya
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // Dmaxiya
ios::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;
}
有一个 的数独,其中的每一行、每一列、每一 的方格内都不重复地包含 到 的每一个十六进制数, 已经完成了一个数独,但是被 逆时针旋转了其中的某几个 的方格,给出旋转后的方格,问最少需要几步才能从原数独逆时针旋转到当前状态。
第一行为一个整数 ,接下来有 组数据,每组数据为一个 的字符矩阵,矩阵中只包含 到 以及 到 这 种字符,表示最终的数独状态。
输出一个非负整数,表示最少需要的操作次数。
输入 |
---|
1681D5A0C9FDBB2F7 0A734B62E167D9E5 5C9B73EF3C208410 F24ED18948A5CA63 39FAED5616400B74 D120C4B7CA3DEF38 7EC829A085BE6D51 B56438F129F79C2A 5C7FBC4E3D08719F AE8B1673BF42A58D 60D3AF25619C30BE 294190D8EA57264C C7D1B35606835EAB AF52A1E019BE4306 8B36DC78D425F7C9 E409492FC7FA18D2 |
输出 |
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 long
const 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 Dmaxiya
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // Dmaxiya
ios::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? |
输出 |
11111 0+0+0 IMPOSSIBLE 10+10 IMPOSSIBLE |
首先如果有
?
在一个单独的零(零前无字符,或者是加号与乘号)后面,就将?
替换为+
,否则将?
替换为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 long
const 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 Dmaxiya
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // Dmaxiya
ios::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 long
const int maxn = 100000 + 100;
int T, n;
int num[maxn];
int main() {
#ifdef Dmaxiya
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // Dmaxiya
ios::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;
}