cf练手day4

http://codeforces.com/contest/1131/problem/B
题意:一场比赛,给出n个时刻的比分,最后一个给出来的是这场比赛最后的比赛,要你求正常比赛下来,最多有多少个时刻是打平的(最初0:0的时候也算一个)

做法:遍历给出的每个时刻的比分,如果当前时刻的最低分大于上一时刻的最高分,则说明这中间出现过平局的时刻,用当前时刻的最低分-上一时刻的最高分再+1就是从上一时刻到当前时刻最多的平局时刻数,如果上一时刻本来就是平局,则ans–。

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <set>
using namespace std;
typedef long long ll;
const int maxn = 10005;

struct node
{
    ll x,y;
}a[maxn];

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        cin>>a[i].x>>a[i].y;
    }
    ll ans = 1;
    for(int i=1; i<=n; i++)
    {
        if(min(a[i].x,a[i].y) >= max(a[i-1].x,a[i-1].y))
        {
            ans += min(a[i].x,a[i].y) - max(a[i-1].x,a[i-1].y) + 1;
        }
        if(a[i-1].x == a[i-1].y)
            ans--;
    }
    cout<<ans;
}

http://codeforces.com/contest/1131/problem/A
题意:给出两个矩形的长、宽,分别是w1,h1,w2,h2(w1>w2),第二个矩形在第一个矩形上面,假设每个矩形都是由单位面积为1的正方形组成的,两个矩形的八个方向上都有单位正方形,两个矩形周围共有多少个单位正方形。

做法:如图分开上下两部分,第一个矩形周围有2h1+2(w1+2)-w2个(因为w1>w2),第二个矩形周围有2*(h2-1)+w2+2个,加起来就是了。
在这里插入图片描述

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <set>
using namespace std;
typedef long long ll;
int main()
{
    ll w1,h1,w2,h2;
    cin>>w1>>h1>>w2>>h2;
    cout<<2*(h1+w1+h2)+4;
}

http://codeforces.com/contest/1131/problem/C
题意:给出n个数,要把它们重新排列,使之形成环后(即1到n也是相邻的),两两的差的最大值最小

做法:排序之后,一个排在前面,一个排在后面,一个排前面,一个排后面……

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int maxn = 105;
int a[maxn],b[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+n);
    int l = 1,r = n;
    for(int i=1; i<=n; i++)
    {
        if(i%2)
            b[l++] = a[i];
        else
            b[r--] = a[i];
    }
    for(int i=1; i<=n; i++)
    {
        printf("%d ",b[i]);
    }
}

http://codeforces.com/contest/1130/problem/C
题意:一个n*n的迷宫,给出起点和终点,0为陆地,1为水,陆地可以走,水不能走,现在要从起点走到终点,由于中间可能会被水隔开,所以可以在任意两个陆地点上架桥,问桥的最短距离。

做法:起点bfs一次,找出从起点开始走可达的所有陆地点,终点bfs一次,找出从终点开始走可达的所有陆地点,然后暴力枚举一下,取最小值。(当起点可以不用架桥就到达终点的时候,最小值就是0啦)

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 55;
char b[maxn][maxn];
int a[maxn][maxn],vis1[maxn][maxn],vis2[maxn][maxn];
int to[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int n;
struct node
{
    int x,y;
}k1[maxn*maxn],k2[maxn*maxn];//k1存起点开始走可以到达的点 k2存终点开始走可以到达的点

bool check1(int x,int y)
{
    if(x >= 1 && x <= n && y >= 1 && y <= n && !vis1[x][y] && a[x][y] == 0)
        return true;
    else
        return false;
}

bool check2(int x,int y)
{
    if(x >= 1 && x <= n && y >= 1 && y <= n && !vis2[x][y] && a[x][y] == 0)
        return true;
    else
        return false;
}

int ans1 = 1,ans2 = 1;
void bfs1(int x,int y,int tx,int ty)//搜索从起点开始可以到达的点
{
    node a,next;
    a.x = x,a.y = y;
    vis1[x][y] = 1;
    queue<node>q;
    q.push(a);
    while(!q.empty())
    {
        a = q.front();
        q.pop();
        if(a.x == tx && a.y == ty)
            return;
        for(int i=0; i<4; i++)
        {
            next.x = a.x + to[i][0];
            next.y = a.y + to[i][1];
            if(check1(next.x,next.y))
            {
                k1[ans1].x = next.x;
                k1[ans1].y = next.y;
                ans1++;
                vis1[next.x][next.y] = 1;
                q.push(next);
            }
        }
    }
    return;
}

void bfs2(int x,int y,int tx,int ty)//搜索终点开始走可以到达的点
{
    node a,next;
    a.x = x,a.y = y;
    vis2[x][y] = 1;
    queue<node>q;
    q.push(a);
    while(!q.empty())
    {
        a = q.front();
        q.pop();
        if(a.x == tx && a.y == ty)
            return;
        for(int i=0; i<4; i++)
        {
            next.x = a.x + to[i][0];
            next.y = a.y + to[i][1];
            if(check2(next.x,next.y))
            {
                k2[ans2].x = next.x;
                k2[ans2].y = next.y;
                ans2++;
                vis2[next.x][next.y] = 1;
                q.push(next);
            }
        }
    }
    return;
}

int len(int x1,int y1,int x2,int y2)
{
    return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
}

int main()
{
    scanf("%d",&n);
    int x1,y1,x2,y2;
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    for(int i=0; i<n; i++)
    {
        scanf("%s",b[i]);
    }
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            a[i+1][j+1] = b[i][j] - '0';
        }
    }
    k1[0].x = x1,k1[0].y = y1;
    k2[0].x = x2,k2[0].y = y2;
    bfs1(x1,y1,x2,y2);
    bfs2(x2,y2,x1,y1);
    if(vis1[x2][y2] == 1)//如果起点可以直接走到终点,则不用搭桥
    {
        printf("0");
    }
    else
    {
        int ans = INF;
        for(int i=0; i<ans1; i++)//枚举起点和终点可以到达的点,算距离取最小值
        {
            for(int j=0; j<ans2; j++)
            {
                int dis = len(k1[i].x,k1[i].y,k2[j].x,k2[j].y);
                ans = min(ans,dis);
            }
        }
        printf("%d",ans);
    }
}

在这里插入图片描述
在这里插入图片描述

由于x值的范围为[max ai,sum ai],所以可以在这个范围里二分,找出x的最小值。
每次搜索到一个可能的x的答案,就判断一下,如果这个x成立,能否在m天内吃完所有食物,如果可以,代表答案在[l,mid]中,如果不行,答案在[mid+1,r]内。判断m天能否吃完所有食物的时候,贪心,只要还吃得下就继续吃。

ps:在这道题中,假设f(i)表示x为i时,需要多少天才吃完所有食物,那么f(i)是个非递增数列,以后遇到这种答案具有单调性的题,都可以用二分答案来做

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int maxn = 100005;
ll a[maxn];
ll n,m;

int check(ll x)
{
    int flag = 1,d = 1;
    ll sum = 0;
    for(int i=1; i<=n; i++)
    {
        if(sum + a[i] <= x)
        {
            sum += a[i];
        }
        else
        {
            sum = a[i];
            d++;
        }
        if(d > m)
        {
            flag = 0;
            break;
        }
    }
    return flag;
}

int main()
{
   scanf("%lld%lld",&n,&m);
   ll l = 0,r = 0;
   for(int i=1; i<=n; i++)
   {
       scanf("%lld",&a[i]);
       l = max(l,a[i]);
       r += a[i];
   }
   ll mid;
   while(l < r)
   {
       mid = (l + r) / 2;
       if(check(mid))
       {
           r = mid;
       }
       else
       {
           l = mid + 1;
       }
   }
   printf("%lld",r);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值