csu-2018年11月月赛Round2-div1题解
A(2191):Wells的积木游戏
Description
Wells有一堆N个积木,标号1~N,每个标号只出现一次 由于Wells是手残党,所以每次只能取出一块积木放在积木顶层 现在Wells想知道至少需要操作几次可以把积木堆成从顶至底标号升序 不论什么都很菜的Wells显然不知道怎么做 所以作为人生赢家的你义不容辞的决定帮助可怜的Wells
Input
第一行一个正整数N
接下来N行,从顶至底描述每块积木的标号
Output
Sample Input
3 3 2 1
Sample Output
2
Hint
样例数据的两次操作(3,2,1)->(2,3,1)->(1,2,3) N<=10^5
题解:
div-1难得的水题,找几个数据看一下就可以发现从最大积木的开始向前找,连续的是有贡献的,比如
2 1 5 3 4 6,6之前只有5这一个连续数字,所以贡献为2,答案就为6 - 2 = 4
代码:
#include<bits/stdc++.h> #define maxn 100005 using namespace std; int a[maxn]; int main() { int n; scanf("%d",&n); int maxx = 0,maxpos; for (int i = 1; i <= n; i++) { scanf("%d",&a[i]); if (a[i] > maxx) { maxx = a[i]; maxpos = i; } } int cnt = 1; for (int i = maxpos - 1; i >= 1; i--) { if (a[i] == maxx - 1) { cnt++; maxx -= 1; } } cout << n - cnt; return 0; }
B(2192):Wells弹键盘
Description
Wells十分羡慕和佩服那些会弹钢琴的人比如子浩君,然而Wells只会弹键盘…… Wells的键盘只有10个键,从1,2,3,……,9,0,如下图所示:
而且作为一个正常人,Wells也有两只手,但是为了显示出自己高超的弹键盘水平,Wells决定每只手只动用一个手指,左手指和右手指,来进行按键操作,初始左右手指分别在5,6两个按键上。每一个单位时间(1s),对于一个手指,Wells可以进行如下操作之一:
- 按下位于手指位置的按键。
- 将手指向左或向右移动一格,当然不能移到键盘外面。
必须注意以下几点:
现在,给Wells得到一个高级键盘谱(一个仅含0~9的非空字符串)可以在梦里弹出不输于钢琴的旋律,但强迫症Wells一定要知道高级键盘谱弹奏最少要几秒才能弹完,但Wells数学太差了,所以Wells求助于你,本世纪最优秀的程序yuan之一来帮助他!
Input
输入文件有若干行,每行描述一组数据。 对于每组数据仅一行,一个数字串s。
Output
输出若干行,每行为对应输入数据的答案。
Sample Input
434 56 57
Sample Output
5 2 2
Hint
对于20%的数据,0<=length(s)<=5,且数据组数不超过3组; 对于100%的数据,0<=length(s)<=100,且数据组数不超过100组; 保证数据中间没有空行;
题解:
设dp[i][j][k]为第i个数字左手在j右手在k时的最小秒数。则j或k肯定有一个是当前的数字。先让j为当前数字枚举k转移,再让k为当前数字枚举j转移。从dp[i - 1][l][r]转移过来,要求是l < r且处理左手在当前数字时l到当前数字的距离+弹奏的1(s)不能比r到k的距离要小,处理右手在当前数字时r到当前数字的距离+弹奏的1(s)不能比l到j的距离小。否则另一只手到达不了另一个数字。
最后f[n][a[n]][i]和f[n][i][a[n]]中最小的即为答案
代码:
#include<bits/stdc++.h> using namespace std; char s[105]; int f[105][15][15]; int a[105]; int main() { while (scanf("%s",s + 1) != EOF) { int n = strlen(s + 1); for (int i = 0; i <= n; i++) { for (int j = 1; j <= 10; j++) { for (int k = 1; k <= 10; k++) { f[i][j][k] = 0x3f3f3f3f; } } } for (int i = 1; i <= n; i++) { if (s[i] == '0') a[i] = 10; else a[i] = s[i] - '0'; } f[0][5][6] = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j < a[i]; j++) { for (int l = 1; l <= 10; L++) { for (int r = l + 1; r <= 10; r++) { int s = abs(r - a[i]) + 1; if (abs(l - j) > s) continue; f[i][j][a[i]] = min(f[i][j][a[i]],f[i - 1][l][r] + s); } } } for (int k = a[i] + 1; k <= 10; k++) { for (int l = 1; l <= 10; L++) { for (int r = l + 1; r <= 10; r++) { int s = abs(l - a[i]) + 1; if (abs(r - k) > s) continue; f[i][a[i]][k] = min(f[i][a[i]][k],f[i - 1][l][r] + s); } } } } int ans = 0x3f3f3f3f; for (int i = 1; i <= 10; i++) { if (a[n] < i) ans = min(f[n][a[n]][i],ans); } for (int i = 1; i <= 10; i++) { if (i < a[n]) ans = min(f[n][i][a[n]],ans); } cout << ans << endl; } return 0; }
C(2195):OR
Description
xrdog有一个有趣的算式
X=(a1ora2ora3or...oraN)?YX=(a1ora2ora3or...oraN)?Y
现给定,问有多少组满足上述算式的,形如 (a1,a2,a3...aN,Y)(a1,Y) 的(N+1)元组。
Input
第一行两个整数 X(1<=X<=109)X(1<=X<=109) 和 N(1<=N<=109)N(1<=N<=109)
Output
打印一个整数,表示所求答案,答案对1e9+7取模。
Sample Input
2 2
Sample Output
6
Hint
有以下6个3元组: (2,1) (0,2,1) (2,1) (1,2) (0,1,2) (1,2)
题解:
先枚举x的每一个因子,找它的二进制下1的个数,每一个1都有2的n次方 - 1的贡献,因为只要在n位中或出这个1就可以了,方法除去全为0的1种,即为2的n次方 - 1
注意枚举因子从1 到 sqrt(x)
代码:
#include<bits/stdc++.h> #define p 1000000007 typedef long long ll; using namespace std; inline ll fastPow(ll a,ll b) { ll ans = 1; while (b) { if (b & 1) { ans = ans * a % p; } a = a * a % p; b >>= 1; } return ans % p; } inline int count(int x) { int ans = 0; while (x) { if (x & 1) ans++; x >>= 1; } return ans; } int main() { int x,n; scanf("%d%d",&x,&n); ll base = fastPow(2,n) - 1; ll ans = 0; for (int i = 1; i * i <= x; i++) { if (x % i == 0) { int num = count(i); ans = (ans + fastPow(base,num)) % p; if (i * i != x) { num = count(x / i); ans = (ans + fastPow(base,num)) % p; } } } cout << ans; return 0; }
D(2202):EL PSY CONGROO
Time Limit: 2 sec
Description
凤凰院凶真又双叒叕踏上了拯救牧濑红莉栖之路,现在有 NN 条世界线 [l1,r1],[l2,r2],...,[lN,rN][l1,rN]。
从这些世界线中选出 KK 个,考虑其交集,即被所 有 KK 个世界线包含的点集。交集必然也是一个世界线,设为 [l,r][l,r],则其长度为 r?lr?l。
只有世界线的交集最大,冈部才有足够的时间完成任务。 请求出所有选出 KK 个世界线的方案中,交集长度最大的。
Input
输入的第一行包含一个整数 TT,代表测试数据的组数。接下来是 TT 组数据。
每组数据的第一行包含两个整数 NN 和 KK 。接下来NN行,每行包含两个整数 lili和 riri,描述一 个世界线。
Output
Sample Input
1 3 2 1 6 2 4 3 6
Sample Output
3
Hint
\[ 1≤T≤1000\1≤K≤N≤10^5\1≤li≤ri≤10^9\∑n≤5?10^5\]
题解:
先对左端点进行升序排序,则选到当前线段的左端点的交集就是当前左端点,同时用小根堆维护右端点的值,使堆大小始终为k,用堆顶的右端点值-当前左端点值更新答案,若超过k,则弹出堆顶的元素,因为它不可能在后面产出更优的答案了
代码:
#include<bits/stdc++.h> #define maxn 100050 using namespace std; inline int getnum() { char c; int ans = 0; int flag = 1; while (!isdigit(c = getchar()) && c != '-'); if (c == '-') flag = -1; else ans = c - '0'; while (isdigit(c = getchar())) ans = ans * 10 + c - '0'; return ans * flag; } struct node { int l,r; bool operator < (const node a) const { return l < a.l; } } a[maxn]; int main() { int t = getnum(); while (t--) { priority_queue<int,vector<int>,greater<int> > q; int n = getnum(),k = getnum(); for (int i = 1; i <= n; i++) { a[i].l = getnum(); a[i].r = getnum(); } sort(a + 1,a + n + 1); int ans = 0; for (int i = 1; i <= n; i++) { if (q.size() >= k) { q.pop(); } q.push(a[i].r); if (q.size() == k) { int x = q.top(); if (x - a[i].l > ans) { ans = x - a[i].l; } } } cout << ans << endl; } return 0; }
E(2203):Mad Scientist
Time Limit: 5 Sec Memory Limit: 256 Mb
Description
凤凰院凶真是个Mad Scientist,他制造了大量Time Machine分布在一块 N×MN×M 的矩形网格区域。每格中要么什么都没有,要么有一个Time Machine。两个Time Machine之 间的距离定义为其曼哈顿距离。
对于 1≤d≤N+M?21≤d≤N+M?2,凶真想知道有多少对Time Machine的距离恰好为 dd。
Input
输入的第一行包含一个整数 TT ,代表测试数据的组数。接下来是 TT 组数据。
每组数据的第一行包含两个整数 NN 和 MM。
接下来 NN 行,每行包含一个长度为 MM 的 0101 串,为‘1’代表网格对应位置中有Time Machine,为‘0’则 代表无。
Output
对于每组数据,输出一行,包含 N+M?2N+M?2 个整数,其中第 dd 个代表距离为 dd 的Time Machine对数。
Sample Input
1 3 4 0011 0000 0100
Sample Output
1 0 1 1 0
Hint
\[ 1≤T≤3\2≤N,M≤300 \]
题解:
此题愉快的不会,估计也会不了了...orz(流下了蒟蒻的泪水)
思路据说是维护左斜线和右斜线的前缀和,或者二维fft,总之我都不会
感想:
div 1太难了!!!早知道多做会div 2了!!div2倒着做做了两个题第三题不会就溜了,没看前两题挺水的,硬怼div 1大失败。下次但愿能从一开始做,这样div 1和div 2都有时间做了,中途开始有点伤
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。