Codeforces Round 361 div2

雪崩,全错掉了GG。前两道题相对之前的难度大一点啊,不过A题有个循环应该是从0开始而不是1开始这样的低级错误不应该犯。B题差不多是一个BFS,但是我当时始终绕着最短路径写来写去,一直各种TLE与WA。C题是一道二分,挺容易的,昨天一直在写B,没做真是可惜。

A

我用DFS写的,相对比较麻烦了。就是按照它的变化次序,来把0-9都试一遍,看有没有满足的。由于那个循环不小心写成了1-9,直接崩了。哎,教训。

B

题目大意就是求从顶点1到其它所有顶点的最短路径值。每两个点之间的距离为下标的差的绝对值。另外每个点还有一个自己的ai,点i到ai的距离为1。共有20w个顶点,我想直接用最短路那儿的方法求一个单源最短路径的,但不管是SPFA(时间复杂度O(kE)),还是用堆优化的dijkstra(时间复杂度O(E+nlogn))都要超时。最后自己又尝试了一个比较怪的dfs,还是超时,到最后就一直卡在这里结束了。第二天看题解发现是用BFS写的,因为DFS扩展的状态太多(每次都有n个),很多带来了重复计算导致效率低下,实际上,由于后面处理的一定比前面处理的距离要长,那么我们只要处理3个状态,即当前状态的前一个、后一个和跳跃的那一个就好了。已经处理过的就不要再处理了。

//
//  main.cpp
//  Codeforces 361 A
//
//  Created by 赵奕 on 16/7/7.
//  Copyright © 2016年 赵奕. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <cmath>
const int MAX = 99999999;
int n,dis[200010],a[200010];
int flag[200010];
using namespace std;
queue<int> q,q2;
void pushing(int x,int y)
{
    if (x < 1 || x > n || flag[x])
        return ;
    q.push(x);
    q2.push(y);
    flag[x] = 1;
    dis[x] = y;
}
int main()
{
    int i,j,s,t;
    cin >> n;
    memset(flag,0,sizeof(flag));
    for (i = 1; i <= n; ++i)
        scanf("%d",&a[i]);
    q.push(1);
    q2.push(0);
    flag[1] = 1;
    while (!q.empty())
    {
        s = q.front();
        q.pop();
        t = q2.front();
        q2.pop();
        pushing(s-1,t+1);
        pushing(s+1,t+1);
        pushing(a[s],t+1);
    }

    for (i = 1; i <= n; ++i)
    {
        cout << dis[i] << " " ;
    }
    return 0;
}

C

题目大意就是有四个数,设第一个数为x,那么第二、三、四个数就分别为kx,k*k*x,k*k*k*x,其中k是任意的。并且这四个数都不能大于n,然后假定符合条件的有m组。题目给定m,问满足有m对的这四个数的最小n为多少。
求最大值的最小。二分。对于每个n,对于每个x,共有[n/(x^3)]个k。让x从2到三次根号下n做一遍循环求一下就好了。

//
//  main.cpp
//  Codeforces 361 C
//
//  Created by 赵奕 on 16/7/7.
//  Copyright © 2016年 赵奕. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <cmath>
const int MAX = 99999999;
typedef long long ll;
ll n,dis[200010],a[200010];
using namespace std;
ll work(ll k)
{
    ll i,j;
    j = 0;
    for (i = 2; i * i * i <= k; ++i)
    {
        j += k/(i*i*i);
    }
    return j;
}
int main()
{
    ll h,i,j,l,r,mid,ans;
    cin >> n;
    l = 1;
    r = 1e18;
    ans = -1;
    while (l <= r)
    {
        mid  = (l+r) >> 1;
        h = work(mid);
        if (h >= n)
        {
            if (h==n)
                ans = mid;
            r = mid-1;
        }
        else
            l = mid+1;
    }

    cout << ans << endl;
    return 0;
}

D

二分+数据结构
题目大意是给你两个长度为20w的数组a、b,求有多少个子区间满足max{a[i]}=min{b[i]}。
我们的做法是固定住区间的右位置,来求有多少个左位置满足条件。然后把这些加起来即可。当右位置固定时,a数组关于左位置的最大值是单调不升的,b数组关于左位置是单调不降的,因此我们可以用二分法来求得有多少满足题意的子区间。我们维护这样的一个值t,使得[t,i]区间,a的最大值比b的最小值一定要小(因为,再往后,位置t仍然没有作用,我们此时把t往后挪)然后在[t,i]区间内找到a的最大值和b的最小值的位置,取它们的较小值为mp,那么从t…mp位置的[j,i]一定都是满足的。
参考小数据:
6
1 2 3 2 1 2
6 7 1 2 3 2

在第三个位置时,A中的最大值3>B中的最小值1,一步步往后拱直至A和B都空了。
在第四个位置时,A中的最大值2=B中的最小值1,此时从4到4都是满足[j,i]满足的。cnt +=1;
在第五个位置,A中的最大值2仍然=B中的最小值1,此时A中的最大值在4,B中的最小值在4,此时从4到4都是满足[j,i]满足的。 cnt+=1
在第五个位置,A中的最大值2仍然=B中的最小值1,此时A中的最大值在6,B中的最小值在6,此时从4到6都是满足[j,i]满足的。cnt+=3;

#include <cstdio>
#include <iostream>
#include <set>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

typedef long long Long;
typedef pair<Long, int> PLI;

int main() {

    int N;
    cin >> N;
    vector<int> A(N),  B(N);
    for(int &v : A)cin >> v;
    for(int &v : B)cin >> v;
    int t = 0;
    Long cnt = 0;
    set<PLI> SB;//按照pair的第一个元素来排,第一个相等的话按第二个来排
    set<PLI,greater<PLI>> SA;//a数组是求最大值,因此按照从大到小的greater来排
    for(int i = 0; i < N; ++i){
        SA.insert(PLI(A[i],i));//每次把当前的数和位置插入set里
        SB.insert(PLI(B[i],-i));
        while(!SA.empty() && !SB.empty() && SA.begin()->first > SB.begin()->first )
        {//如果当前A序列的最大值比B的最小值要大,显然[t,i]区间没有满足的,那么把t往前拱,使得把A的大的弄掉,B的小的弄掉
            SA.erase(SA.lower_bound(PLI(A[t],t)));
            SB.erase(SB.lower_bound(PLI(B[t],-t)));
            t++;
        }
        if(!SA.empty() && !SB.empty() && SA.begin()->first == SB.begin()->first){//如果此时A的最大值和B的最小值相等。那么计算有多少个j使得在[j,i]满足题意。
            int mp = min( SA.begin()->second, -(SB.begin()->second) );//A里面第一个存放的是t到i位置的最大值的位置
            cnt += mp - t + 1;//j属于[t,mp]都满足[j,i]区间...
        }
    }
    cout << cnt << endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值