Codeforces Round #353 (Div. 2) ABCDE 题解 python

Problems
 
 
#Name  
A
standard input/output
1 s, 256 MB
Submit Add to favourites x3509
B
standard input/output
1 s, 256 MB
Submit Add to favourites x2519
C
standard input/output
1 s, 256 MB
Submit Add to favourites x724
D
standard input/output
2 s, 256 MB
Submit Add to favourites x1008
E
standard input/output
2 s, 256 MB
Submit Add to favourites x239

 

以后cf的题能用python写的我就python了,因为以后没正式比赛参加了,不必特地用C++。python写得快,也容易看得懂,我最近也比较需要练习这个。当然有的题C++写得少我还是用C++。

 

A. Infinite Sequence

题意:给出a,b,c,求是否a加若干个c能得到b,是就输出YES,否就输出NO

题解:

就特判各种情况,一般情况是看(b-a)%c==0

特殊情况,依次判断:

1.a==b,YES

2.c==0,NO

3.b-a与c不同号,NO

4.c小于零,则把b-a和c都变正数再判。

 1 def gank(a,b,c):
 2     d = b - a
 3     if(d==0):
 4         return True
 5     if(c==0):
 6         return False
 7     if((d<0 and c>0) or(c<0 and d>0)):
 8         return False
 9     if(c<0):
10         d*=-1
11         c*=-1
12     if(d%c==0):
13         return True
14     else:
15         return False
16 
17 a,b,c = map(int , raw_input().split(' '))
18 if(gank(a,b,c)):
19     print "YES"
20 else:
21     print "NO"
View Code

 

 

B. Restoring Painting

题意:有个3*3的九宫格,每个格子能填1~n中任意的数(n由输入给出)。要求其中任意2*2的格子中4个数的和与其他各个2*2格子都相等。

输入n,a,b,c,d,求剩下的数有多少种填法。(可能为0种)

题解:

固定中间的为1,则4种2*2格子的和,要是使得一个相邻的数比较大的角为1,另一个相邻数字比较小的角为n,格子和也没法相等的话,就不行,所以要找2*2格子的最小值和最大值,判断可行性。

比如有这种情况,最大那个角填1,最小那个角最少只能填x,则它们有(n-x+1)种情况(最小的那个角为x,为x+1,直到为n)。

中间那个数其实随便填,不影响,所以最后答案(n-x+1)*n

 1 def gank(n,A,b,c,d):
 2     a = [0]*4
 3     a[0] = A+b
 4     a[1] = A+c
 5     a[2] = b+d
 6     a[3] = c+d
 7     mi = 1e9
 8     ma = 0
 9     for i in range(4):
10         ma = max(ma,a[i])
11         mi = min(mi,a[i])
12     if(1 + 1 + ma > 1+n+mi):
13         return 0
14     x = ma - mi + 1
15     y = n - x + 1
16     return y*n
17 
18 
19 n,a,b,c,d = map(int , raw_input().split(' '))
20 print gank(n,a,b,c,d)
View Code

 

 

C. Money Transfers

题意:

有一圈银行,瓦夏在各个银行存的钱为a[i](可能为负数,代表借了钱),sum(a[i])==0,瓦夏可以进行一种操作:把一个银行的若干钱转到相邻的银行。求最少多少次操作能把所有银行存款归零。

题解:

这题,难!过D的人都比过C的多,我是不会的,看的题解。

首先考虑,若有一个区间[L,R],使得其中的sum(a[i])==0,则这个区间可以单独转钱就能归零,用的操作数为R-L。如果一个银行为0,它可以单独当一个区间。最后,我们可以得到若干个相邻的区间,总操作数为(n - 区间数)。

所以问题转化为最大化这种区间数。

为了找到和为0的区间,我们算一波前缀和。

当有两个位置的前缀和相同,说明这两个之间的各个元素和为0!

当很多个位置的前缀和相同,说明这些位置分成的各个区间,每个区间和为0。

我们就算一波各个前缀和出现的次数,出现次数最多的那个就是按照最碉的分区间法得到的最多区间数。

 1 def farm(n, a):
 2     dic = dict()
 3     re=0
 4     sum = 0
 5     for i in a:
 6         sum += i
 7         if not sum in dic:
 8             dic[sum]=0
 9         dic[sum]+=1
10         re = max(re,dic[sum])
11     return n - re
12 
13 n = input()
14 a = map(int, raw_input().split(' '))
15 ans = farm(n, a)
16 print ans
View Code

 

 

D. Tree Construction

题意:给出一个各不相同的序列,插入二叉搜索树中,二叉搜索树不作平衡处理,直接强插,输出除了第一个点之外各个点的父亲的值。

题解:

直接强插,O(n^2),会爆。我不懂,我又看的题解会的。

这个朴素二叉搜索树的特性,是我要插x,那它肯定要成为之前插入过的数中比它小的中最大的数的右儿子 或者 比它大的数中最小的数的左儿子。

所以我们就找用别的平衡树找到这2个数在朴素树中的位置。然后根据性质,肯定只有一个地方能插,我们就插。(可恶,我不懂为什么,对这个树的性质理解不完全)

可以用C++的STL的set和map来当平衡树,我就用C++写了。

 1 //#pragma comment(linker, "/STACK:102400000,102400000")
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<iostream>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<cmath>
 8 #include<map>
 9 #include<set>
10 #include<stack>
11 #include<queue>
12 using namespace std;
13 
14 #define MZ(array) memset(array, 0, sizeof(array))
15 #define MF1(array) memset(array, -1, sizeof(array))
16 #define MINF(array) memset(array, 0x3f, sizeof(array))
17 #define REP(i,n) for(i=0;i<(n);i++)
18 #define FOR(i,x,n) for(i=(x);i<=(n);i++)
19 #define FORD(i,x,y) for(i=(x);i>=(y);i--)
20 #define RD(x) scanf("%d",&x)
21 #define RD2(x,y) scanf("%d%d",&x,&y)
22 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
23 #define WN(x) printf("%d\n",x);
24 #define RE  freopen("D.in","r",stdin)
25 #define WE  freopen("huzhi.txt","w",stdout)
26 #define MP make_pair
27 #define PB push_back
28 #define PF push_front
29 #define PPF pop_front
30 #define PPB pop_back
31 template<class T>inline void OA(const T &a,const int &st,const int &ed) {
32     if(ed>=st)cout<<a[st];
33     int i;
34     FOR(i,st+1,ed)cout<<' '<<a[i];
35     puts("");
36 }
37 typedef long long LL;
38 typedef unsigned long long ULL;
39 
40 const double PI=acos(-1.0);
41 const double EPS=1e-10;
42 const int MAXN=111111;
43 const int MAXM=33;
44 
45 struct Node {
46     int value;
47     Node *son[2];
48     Node() {}
49     Node(int v) {
50         value = v;
51         son[0]=son[1]=NULL;
52     }
53 } root;
54 
55 typedef pair<int, Node*> PIN;
56 set<PIN> s;
57 int n;
58 int a[MAXN];
59 int ans[MAXN];
60 
61 void farm() {
62     root = Node(a[0]);
63     s.clear();
64     s.insert(MP(a[0], &root));
65     int i;
66     FOR(i,1,n-1) {
67         set<PIN>::iterator it = s.upper_bound(MP(a[i],(Node*)NULL));
68         if(it!=s.end() and it->second->son[0]==NULL) {
69             (it->second)->son[0] = new Node(a[i]);
70             s.insert(MP(a[i], it->second->son[0]));
71             ans[i] = it->second->value;
72         } else {
73             set<PIN>::iterator it2 = it;
74             if(it2!=s.begin())it2--;
75             it2->second->son[1] = new Node(a[i]);
76             s.insert(MP(a[i], it2->second->son[1]));
77             ans[i] = it2->second->value;
78         }
79 
80     }
81 }
82 
83 
84 int main() {
85     int i;
86     RD(n);
87     REP(i,n)RD(a[i]);
88     farm();
89     OA(ans,1,n-1);
90     return 0;
91 }
View Code

 

 

E. Trains and Statistic

题意:有一个一条直线的地铁线路。给出a数组,每个站点i只能买到去往[i+1, a[i]]内的票。设p(i,j)为从i到j所需要的最少票数,求对所有ij的p(i,j)的和。(1=<i<j<=n)

题解:

设f[x]为从站点x到它之后所有站点票数的和。

简单设想,f[x]的值对f[x-1] f[x-2]等等各个值的计算是有用的。

当从一个站点i到不了所有点时,会到它能到的点中a[i]最大的点x。这时就能用到f[x]。

b[i] = x-i + b[x] + n - a[i]

其中自己能走i+1~x-1点,用x-i票。

x能到x+1~n,用b[x]票。

x能走的那些中,x+1 ~ a[i]是i自己能走的,把x走的当做自己走的,更远的要自己买票走到x,要n - a[i]张票。

综合起来就是上面那个公式。

x能走的肯定比a[i]远,因为a[a[i]]肯定要大于a[i]。

 

这样,我们要做的就是每次找出区间[i+1, a[i]]中a[x]最大的x。

这可以用各种RMQ方法。不能用单调区间O(1)求,因为这个区间不是纯粹向左移动的,左界是一个个往左,右界是会来回动的。

所以我们可以维护一个只进不出的单调下降队列,然后用二分找。

O(nlogn)

 1 from collections import deque
 2 
 3 def argmax(q,z):
 4     l = 0
 5     r = len(q) - 1
 6     while(l<=r):
 7         mid = (l+r)/2
 8         x = q[mid]['i']
 9         if(x<=z):
10             r = mid - 1
11         else:
12             l = mid + 1
13     return q[l]['i']
14 
15 def gank(n,A):
16     a = [0]*(n+1)
17     a[1:] = A
18     b = [0]*(n+1)
19     b[n-1] = 1
20     q = deque()
21     q.append({'i':n-1, 'a':a[n-1]})
22     for i in range(n-2, 0, -1):
23         if(a[i]>=n):
24             b[i] = n-i
25         else:
26             x = argmax(q,a[i])
27             b[i] = x-i + b[x] + n - a[i]
28         while(len(q)>0 and q[-1]['a'] < a[i]):
29             q.pop()
30         q.append({'i':i, 'a':a[i]})
31     return sum(b)
32 
33 n = int(raw_input())
34 a = map(int , raw_input().split(' '))
35 print gank(n,a)
View Code

 

转载于:https://www.cnblogs.com/yuiffy/p/5503770.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值