codeforces 675 A~E(Round #353 Div. 2) python and C++ 解法

来源:互联网 发布:csgo举报机器人软件 编辑:程序博客网 时间:2024/06/05 21:31

PROBLEM LIST

official tutorial

Explanation

I use python in Problem A, B & E.
while in C and D, I found it easier to write in C++.(for I can use STL to reduce my work)

A题:

题意:给出a,b,c,求是否a加若干个c能得到b,是就输出YES,否就输出NO
思路:(b-a)%c==0

a, b, c = map(int, input().split(' '))if ((a != b and c == 0) or (b > a and c < 0)):    print("NO")elif ((a == b) or (b > a and c > 0 and ((b - a) % c == 0)) or (a > b and c < 0 and ((a - b) % c == 0))):    print("YES")else:    print("NO")

B题:

题意:给出a,b,c,求是否a加若干个c能得到b,是就输出YES,否就输出NO
思路:(b-a)%c==0

a, b, c = map(int, input().split(' '))if ((a != b and c == 0) or (b > a and c < 0)):    print("NO")elif ((a == b) or (b > a and c > 0 and ((b - a) % c == 0)) or (a > b and c < 0 and ((a - b) % c == 0))):    print("YES")else:    print("NO")

C题:

按和为0切段,答案是(总数-段数),一共有mp[sum]段可以使和为0
次数最少,就要使段数最多–>>贪心算法+排序+map+数据结构
注意,所有点相当于一个环,就是说可以首尾相连

#include <iostream>#include <algorithm>#include <map>using namespace std;int main(){    int n;    scanf("%d",&n);    map<long long,int>mp;    long long sum=0;    int ans=n-1,aa;//初始化只有一段     for (int i=0;i<n;i++)    {        scanf("%d",&aa);        sum+=aa;        mp[sum]++; //分成mp[sum]个部分        ans=min(ans,n-mp[sum]);    }    printf ("%d\n",ans);    return 0;}

D题:

binary search tree
题意: 二叉搜索树,不用旋转,强插,输出除了第一个点之外所有点的父亲值
可以用C++的STL的set和map来当平衡树。

#include<iostream>#include<algorithm>#include<map>#include<set>using namespace std;/*binary search tree题意: 二叉搜索树,不用旋转,强插,输出除了第一个点之外所有点的父亲值可以用C++的STL的set来当平衡树。思路:找到v,把之前插入的放入set,用upper_bound找到l<v<r*/int main(){    ios_base::sync_with_stdio(false); cin.tie(0);    set<int>numbers;    map<int, int>left;    map<int, int>right;    int n, v;    cin >> n >> v;    numbers.insert(v);    for (int i = 0; i < n - 1; i++)    {        cin >> v;        auto it = numbers.upper_bound(v);        int res;        if (it != numbers.end() && left.count(*it) == 0)        {//upper_bound的结果没在最后也没有左子树,就是插入这里            left[*it] = v;            res = *it;        }        else        {            it--;            right[*it] = v;            res = *it;        }        numbers.insert(v);        cout << res;        if (i != n - 2)            cout << ' ';    }    return 0;}

E题:

题意:

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

思路:

dp[i] 是从i到后面所有站点的最小票数和
当从一个站点i到不了所有点时,会到它能到的点中a[i]最大的点x。这时就能用到dp[x]。
其中自己能走i+1~x-1点,用x-i票
x能到x+1~n,用b[x]票
x能走的那些中,x+1 ~ a[i]是i自己能走的,把x走的当做自己走的,更远的要自己买票走到x,要n - a[i]张票
得到:dp[i] = x-i + dp[x] + n - a[i]
x能走的肯定比a[i]远,因为a[a[i]]肯定要大于a[i]
这样,我们要做的就是每次找出区间[i+1, a[i]]中a[x]最大的x
这可以用各种RMQ方法,不能用单调区间O(1)求,因为这个区间不是纯粹向左移动的,左界是一个个往左,右界是会来回动的。
所以可以维护一个只进不出的单调下降队列,然后用二分找。O(nlogn)

#!/usr/bin/env python# -*- coding: utf-8 -*-# @Time    : 2017/3/22 15:35# @Author  : mazicwong# @File    : 675E DP+greedy.py'''英文: buy only tickets to stations from i+1 to ai inclusive (inclusive 表示包含在这个路段内的)give:na1,a2...an-1使用:deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:debug用法说明:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431953239820157155d21c494e5786fce303f3018c86000'''from collections import dequedef argmax(que, z): #二分求[i+1, a[i]]中a[x]最大的x    l = 0    r = len(que) - 1    while (l <= r):        mid = int((l + r) / 2)        x = que[mid]['i']        if (x <= z):            r = mid - 1        else:            l = mid + 1    return que[l]['i']def solve(n, A):    a = [0] * (n + 1)    a[1:] = A    dp = [0] * (n + 1)    dp[n - 1] = 1    que = deque()    que.append({'i': n - 1, 'a': a[n - 1]})    for i in range(n - 2, 0, -1):        if (a[i] >= n):            dp[i] = n - i        else:            x = argmax(que, a[i])            dp[i] = x - i + dp[x] + n - a[i]        while (len(que) > 0 and que[-1]['a'] < a[i]):            que.pop()        que.append({'i': i, 'a': a[i]})    return sum(dp)n = int(input())a = map(int, input().split(' '))print(solve(n, a))
1 0
原创粉丝点击