Codeforces Round #333 (Div. 2)

因为现在太渣了只能做div2;争取每次div2都做出4题,然后提高自己能力之后,再来个5题全过,所以下面只有四题的题解;

题A

题意:给你两个数,但是用的是数组来表示,每个数有n个数,然后有一个基数base,也就是base进制的意思,然后问你这两个数那个比较大。

题解:水题,直接开龙龙模拟

 1 /*zhen hao*/
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4
 5 typedef long long ll;
 6 int val[50];
 7
 8 int main() {
 9   //freopen("case.in", "r", stdin);
10   int n, base;
11   cin >> n >> base;
12   for (int i = 0; i < n; i++) cin >> val[i];
13   ll x = 1, num1 = 0, num2 = 0;
14   for (int i = n - 1; i >= 0; i--) {
15     num1 = num1 + val[i] * x;
16     x *= base;
17   }
18   cin >> n >> base;
19   for (int i = 0; i < n; i++) cin >> val[i];
20   x = 1;
21   for (int i = n - 1; i >= 0; i--) {
22     num2 = num2 + val[i] * x;
23     x *= base;
24   }
25   if (num1 > num2) puts(">");
26   else if (num1 < num2) puts("<");
27   else puts("=");
28 }

代码君

题B

题意:给你一串数字,保证相邻两个一定满足|ai – ai+1| <= 1,然后定义一个区间:这个区间的最大值和最小值的差不超过一,也就是max – min <= 1,然后问你最长的区间是多少。

题解:dp[v][0]表示[v-1,v],dp[v][1]表示[v,v+1];然后就是来一个数,更新相应的状态,然后要注意的是因为要求的是区间,也就是连续,所以记得相应的状态变成0,也就是dp[v-1][0],dp[v+1][1],还有dp[v+2]和dp[v-2]的状态都要还原成0,就是没注意这个wa了几次。

 1 /*zhen hao*/
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4
 5 const int maxn = 100000 + 100;
 6 int val[maxn], dp[maxn][3];
 7
 8 int main() {
 9   //freopen("case.in", "r", stdin);
10   int n;
11   scanf("%d", &n);
12   for (int i = 1; i <= n; i++)
13     scanf("%d", val + i);
14   memset(dp, 0, sizeof(dp));
15   int ans = 0;
16   for (int i = 1; i <= n; i++) {
17     int v = val[i];
18     dp[v][0]++; dp[v][1]++;
19     dp[v - 1][1]++; dp[v + 1][0]++;
20     dp[v - 1][0] = dp[v + 1][1] = 0;
21     if (i > 2) dp[v - 2][0] = dp[v - 2][1] = 0;
22     dp[v + 2][0] = dp[v + 2][1] = 0;
23     ans = max(ans, dp[v][0]);
24     ans = max(ans, dp[v][1]);
25     ans = max(ans, dp[v - 1][1]);
26     ans = max(ans, dp[v + 1][0]);
27   }
28   cout << ans << endl;
29 }

代码君

题C

题意:给你一副图,图里面的边都是铁路,给火车行驶,然后另外没有给出的边就是巴士行驶的,问你火车和巴士能不能都从1到达n,然后max{ t1,t2}是多少。

题解:水题,直接bfs一次即可。

 1 /*zhen hao*/
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4
 5 const int maxn = 500;
 6 int G[maxn][maxn], dist[maxn];
 7 int n, m;
 8
 9 int bfs(int flag) {
10   memset(dist, -1, sizeof dist);
11   dist[1] = 0;
12   queue<int> Q;
13   Q.push(1);
14   while (!Q.empty()) {
15     int u = Q.front(); Q.pop();
16     if (u == n) return dist[u];
17     for (int i = 1; i <= n; i++) {
18       if (G[u][i] != flag)  continue;
19       if (dist[i] == -1) {
20         dist[i] = dist[u] + 1;
21         Q.push(i);
22       }
23     }
24   }
25   return -1;
26 }
27
28 int main() {
29   //freopen("case.in", "r", stdin);
30   scanf("%d%d", &n, &m);
31   memset(G, 0, sizeof(G));
32   for (int i = 0; i < m; i++) {
33     int u, v;
34     scanf("%d%d", &u, &v);
35     G[u][v] = G[v][u] = 1;
36   }
37   int t1 = bfs(0), t2 = bfs(1);
38   if (t1 == -1 || t2 == -1) puts("-1");
39   else printf("%d\n", max(t1, t2));
40 }

代码君

题D

题意:定义一种常数:

给你一串序列,有n个整数,然后有q个询问,每个询问是一个区间[l,r],问你这个区间的所有子区间的那个常数之和是多少,输出和;

题解:先观察这个式子可以发现,实际上j-i = 1的时候是最大的,也就是不管取什么区间都是这分母都是1,所以就是在[i,j]这个区间中的[i,i+1],[i+1,i+2]中取最大值,然后如果单纯枚举是O(n^2q),时间上行不通,最多只能跑到case10,这里用的是单调栈优化。

现在结合我的推导详细说一下这个算的过程:

我们知道单调栈的功能是快速算出左边比它大的,右边比它大的元素有多少个,也可以倒过来求左边和右边比自己小的有多少个,而且整个做法是O(n)。只要知道这个怎样套到这道题呢?我们知道区间里面的数每一个都有可能是一个子区间的最大值,那么这个次数是多少呢?看图:

(7 (8) 2 1 2)

很显然这个8倍这5个数字共享了,答案是这个8的区间一定包含了8这个元素,有多少个呢?答案是8个,8的左边有两种选择0和1,8的右边有两种选择0123,所以2*4 = 8;也就是(左边比8小的元素 +1) × (右边比8小的元素 +1);这个就是答案。然后依次用单调栈算出即可。复杂度O(nq)

 1 /*zhen hao*/
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4
 5 typedef long long ll;
 6 const int maxn = 1e5 + 100;
 7 ll val[maxn];
 8
 9 struct Node {
10   ll val;
11   int sum;
12 };
13
14 stack<Node> S;
15
16 ll f(ll x) {
17   return x > 0 ? x : -x;
18 }
19
20 int main() {
21  // freopen("case.in", "r", stdin);
22   int n, q;
23   scanf("%d%d", &n, &q);
24   for (int i = 1; i <= n; i++)  cin >> val[i];
25   while (q--) {
26     int l, r;
27     scanf("%d%d", &l, &r);
28     ll ans = 0;
29     for (int i = l + 1; i <= r; i++) {
30       ll v = f(val[i] - val[i - 1]);
31       int temp = 0;
32       while (!S.empty() && v >= S.top().val) {
33         ans += 1LL * S.top().sum * (temp + 1) * S.top().val;
34         temp += S.top().sum;
35         S.pop();
36       }
37       S.push((Node){v, temp + 1});
38     }
39     int temp = 0;
40     while (!S.empty()) {
41       ans += 1LL * S.top().sum * (temp + 1) * S.top().val;
42       temp += S.top().sum;
43       S.pop();
44     }
45     cout << ans << endl;
46   }
47   return 0;
48 }

代码君

时间: 2025-01-21 14:14:48

Codeforces Round #333 (Div. 2)的相关文章

Codeforces Round #333 (Div. 1)--B. Lipshitz Sequence 单调栈

题意:n个点, 坐标已知,其中横坐标为为1~n. 求区间[l, r] 的所有子区间内斜率最大值的和. 首先要知道,[l, r]区间内最大的斜率必然是相邻的两个点构成的. 然后问题就变成了求区间[l, r]内所有子区间最大值的和. 这个问题可以利用单调栈来做. 每次找到当前点左面第一个大于当前值的点, 然后更新答案. 姿势很多. 1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import

Codeforces Round #279 (Div. 2) ABCD

Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems # Name     A Team Olympiad standard input/output 1 s, 256 MB  x2377 B Queue standard input/output 2 s, 256 MB  x1250 C Hacking Cypher standard input/output 1 s, 256 MB  x740 D Chocolate standard input/

Codeforces Round #633 (Div. 2)

Codeforces Round #633(Div.2) \(A.Filling\ Diamonds\) 答案就是构成的六边形数量+1 //#pragma GCC optimize("O3") //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<bits/stdc++.h> using namespace std; function<void(void)> __

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我

[Codeforces] Round #352 (Div. 2)

人生不止眼前的狗血,还有远方的狗带 A题B题一如既往的丝帛题 A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少 题解:打表,输出 1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd

Codeforces Round #273 (Div. 2)

Codeforces Round #273 (Div. 2) 题目链接 A:签到,仅仅要推断总和是不是5的倍数就可以,注意推断0的情况 B:最大值的情况是每一个集合先放1个,剩下都丢到一个集合去,最小值是尽量平均去分 C:假如3种球从小到大是a, b, c,那么假设(a + b) 2 <= c这个比較明显答案就是a + b了.由于c肯定要剩余了,假设(a + b)2 > c的话,就肯定能构造出最优的(a + b + c) / 3,由于肯定能够先拿a和b去消除c,而且控制a和b成2倍关系或者消除

Codeforces Round #339 (Div. 2) B. Gena&#39;s Code

B. Gena's Code It's the year 4527 and the tanks game that we all know and love still exists. There also exists Great Gena's code, written in 2016. The problem this code solves is: given the number of tanks that go into the battle from each country, f