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);
}