SCAU2021春季个人排位赛第九场 (部分题解)

A题

CodeForces - 864C 

A bus moves along the coordinate line Ox from the point x = 0 to the point x = a. After starting from the point x = 0, it reaches the point x = a, immediately turns back and then moves to the point x = 0. After returning to the point x = 0 it immediately goes back to the point x = a and so on. Thus, the bus moves from x = 0 to x = a and back. Moving from the point x = 0 to x = a or from the point x = a to x = 0 is called a bus journey. In total, the bus must make k journeys.

The petrol tank of the bus can hold b liters of gasoline. To pass a single unit of distance the bus needs to spend exactly one liter of gasoline. The bus starts its first journey with a full petrol tank.

There is a gas station in point x = f. This point is between points x = 0 and x = a. There are no other gas stations on the bus route. While passing by a gas station in either direction the bus can stop and completely refuel its tank. Thus, after stopping to refuel the tank will contain b liters of gasoline.

What is the minimum number of times the bus needs to refuel at the point x = f to make k journeys? The first journey starts in the point x = 0.

Input

The first line contains four integers abfk (0 < f < a ≤ 106, 1 ≤ b ≤ 109, 1 ≤ k ≤ 104) — the endpoint of the first bus journey, the capacity of the fuel tank of the bus, the point where the gas station is located, and the required number of journeys.

Output

Print the minimum number of times the bus needs to refuel to make k journeys. If it is impossible for the bus to make k journeys, print -1.

Examples

Input

6 9 2 4

Output

4

Input

6 10 2 4

Output

2

Input

6 5 4 3

Output

-1

Note

In the first example the bus needs to refuel during each journey.

In the second example the bus can pass 10 units of distance without refueling. So the bus makes the whole first journey, passes 4 units of the distance of the second journey and arrives at the point with the gas station. Then it can refuel its tank, finish the second journey and pass 2 units of distance from the third journey. In this case, it will again arrive at the point with the gas station. Further, he can refill the tank up to 10 liters to finish the third journey and ride all the way of the fourth journey. At the end of the journey the tank will be empty.

In the third example the bus can not make all 3 journeys because if it refuels during the second journey, the tanks will contain only 5 liters of gasoline, but the bus needs to pass 8 units of distance until next refueling.

 

题意:

车从0到a为一次旅程,到a后立刻掉头去0,也为一次旅程。每走一个格子就消耗一升油。一开始先有B升油。0到a之间有且只有一个加油站,加油站上可以将油补到B,即补满。问走k次旅程最少加油次数。

 

一开始以为是思维题,弄弄不等式能够写出来,但是写不出来。

后来看了看k的数据范围,就决定直接按照k去模拟,也就是一次一次旅程模拟。

既然是最少加油次数,那么我们就是能不加油就不加油。当你走到对面折返回来的时候还能到加油站,那么这个时候你走去对面的这一旅程就不用加油,折返回来的时候再次判断是否可以不在加油站停下加油。

但是要注意不能够完成k次旅程的情况。

在两边端点,但是油不够走到加油站。

或者是在加油站加满油了,还是走不到下一个目标点。

 

代码:

#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <algorithm>
#include <stdlib.h>
#include <cstdlib>
#include <math.h>
#include <cmath>
#include <string>
#include <string.h>
#include <cstring>
#include <vector>
#include <queue>
#include <list>
#include <stack>

using namespace std;

long long a,b,f,k;

void ready()
{
    ios::sync_with_stdio(false),cin.tie(0);
    cin>>a>>b>>f>>k;
}

long long work()
{
   long long fuel=b,ans=0;
   for(int i=1;i<=k;i++)
   {
       if(fuel>=a*(k-i+1))
         break;
       if(i&1)
       {
           if(fuel<f)
              return -1;
           if(fuel>=2*a-f)
           {
               fuel-=a;
               continue;
           }
           if(a-f>b)
             return -1;
           fuel=b-a+f;
           ans++;
       }
       else
       {
           if(fuel<a-f)
             return -1;
           if(fuel>=a+f)
           {
               fuel-=a;
               continue;
           }
           if(f>b)
              return -1;
           fuel=b-f;
           ans++;
       }
       //cout<<ans<<'\n';
   }
   return ans;
}

int main()
{
    ready();
    cout<<work();
     return 0;
}

 

 

D题

LibreOJ - 10096 

题目描述

原题来自:APIO 2009

Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定,在每个路口都设立了一个 Siruseri 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。

Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆祝他的胜利。

使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额。他希望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可以经过同一路口或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机里面就不会再有钱了。

例如,假设该城中有 6 个路口,道路的连接情况如下图所示:

11.jpg

市中心在路口 1,由一个入口符号 → 来标识,那些有酒吧的路口用双圈来表示。每个 ATM 机中可取的钱数标在了路口的上方。在这个例子中,Banditji 能抢劫的现金总数为 47,实施的抢劫路线是:1−2−4−1−2−3−5。

输入格式

第一行包含两个整数 N,M。N 表示路口的个数,M 表示道路条数。

接下来 M 行,每行两个整数,这两个整数都在 1 到 N 之间,第 i+1 行的两个整数表示第 i 条道路的起点和终点的路口编号。

接下来 N 行,每行一个整数,按顺序表示每个路口处的 ATM 机中的钱数。

接下来一行包含两个整数 S,P,S 表示市中心的编号,也就是出发的路口。P 表示酒吧数目。

接下来的一行中有 P 个整数,表示 P 个有酒吧的路口的编号。

输出格式

输出一个整数,表示 Banditji 从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。

样例

InputOutput
6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1
5
1 4
4
3
5
6
47

数据范围与提示

50% 的输入保证 N,M≤3000。

100% 的输入保证 N,M≤500000。

每个 ATM 机中可取的钱数为一个非负整数且不超过 4000。输入数据保证你可以从市中心沿着 Siruseri 的单向的道路到达其中的至少一个酒吧。

 

题解:

缩点之后跑一次 最长路。

幸好有板子,写了Tarjan出来。上次考的是无向图Tarjan,这次就来了有向图Tarjan缩点了。

一开始最后求最大钱数,用了DFS超时了。最后改成SPFA做才对了。

 

#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <algorithm>
#include <stdlib.h>
#include <cstdlib>
#include <math.h>
#include <cmath>
#include <string>
#include <string.h>
#include <cstring>
#include <vector>
#include <queue>
#include <list>
#include <stack>

using namespace std;


const int N=500005;

int n,m,s,ai;
int p[N],pi,nex[N],to[N];
int val[N];
int a[N];

void read_in(int u,int v)
{
    pi++;nex[pi]=p[u];p[u]=pi;to[pi]=v;
}

void ready()
{
    ios::sync_with_stdio(false),cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int ui,vi;
        cin>>ui>>vi;
        read_in(ui,vi);
    }
    for(int i=1;i<=n;i++)
        cin>>val[i];
    cin>>s>>ai;
    for(int i=1;i<=ai;i++)
        cin>>a[i];
}

int low[N],pre[N],col[N],sum[N],cnt,dfs_time;
stack<int> S;

void Tarjan(int u)
{
    low[u]=pre[u]=++dfs_time;
    S.push(u);
    for(int k=p[u],v=to[k];k;k=nex[k],v=to[k])
    {
        if(!pre[v])
        {
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else
            if(!col[v])
              low[u]=min(low[u],pre[v]);
    }
    if(pre[u]==low[u])
    {
        ++cnt;
        int now=0;
        while(now!=u)
        {
            now=S.top();
            S.pop();
            col[now]=cnt;
            sum[cnt]+=val[now];
        }
    }
}

vector<int> ma[N];
int ans[N],Ans;
bool vis[N];
queue<int> q;

void SPFA()
{
    for(int i=1;i<=cnt;i++)
        ans[i]=sum[i];
    q.push(col[s]);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=false;
        for(int i=0;i<ma[u].size();i++)
        {
            int v=ma[u][i];
            if(ans[v]<ans[u]+sum[v])
            {
                ans[v]=ans[u]+sum[v];
                if(!vis[v])
                {
                    vis[v]=true;
                    q.push(v);
                }
            }
        }
    }
}

int main()
{
    ready();
    for(int i=1;i<=n;i++)
        if(!pre[i])
          Tarjan(i);

    for(int u=1;u<=n;u++)
    {
        for(int k=p[u],v=to[k];k;k=nex[k],v=to[k])
        {
            if(col[u]!=col[v])
            {
                ma[col[u]].push_back(col[v]);
            }
        }
    }
    vis[col[s]]=true;
    SPFA();
    for(int i=1;i<=ai;i++)
        Ans=max(Ans,ans[col[a[i]]]);
    cout<<Ans;

    return 0;
}

 

 

 

F题

CodeForces - 484A 

Let's denote as  the number of bits set ('1' bits) in the binary representation of the non-negative integer x.

You are given multiple queries consisting of pairs of integers l and r. For each query, find the x, such that l ≤ x ≤ r, and  is maximum possible. If there are multiple such numbers find the smallest of them.

Input

The first line contains integer n — the number of queries (1 ≤ n ≤ 10000).

Each of the following n lines contain two integers li, ri — the arguments for the corresponding query (0 ≤ li ≤ ri ≤ 1018).

Output

For each query print the answer in a separate line.

Examples

Input

3
1 2
2 4
1 10

Output

1
3
7

 

 

题意:

给出l和r,找到一个x,l<=x<=r,并且x在二进制下的1是最多的。如果有多个答案找最小的。

 

既然比l小,l的每一位 或1 一下,直到大于r之前那个数就是答案。

 

#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <algorithm>
#include <stdlib.h>
#include <cstdlib>
#include <math.h>
#include <cmath>
#include <string>
#include <string.h>
#include <cstring>
#include <vector>
#include <queue>
#include <list>
#include <stack>

using namespace std;

long long l,r;
int hl,hr;
void ready()
{
    cin>>l>>r;
}

int H(int temp)
{
    int cnt=0;
    while(temp)
    {
        cnt++;
        temp>>=1;
    }
    return cnt;
}

void slove()
{
    ready();
    long long t=1;
    while((l|t)<=r)
    {
        l=l|t;
        t<<=1;
    }
    cout<<l<<'\n';
}

int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int T;
    cin>>T;
    for(int i=1;i<=T;i++)
    {
        slove();
    }

    return 0;
}

 

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值