UVA10382 最少区间覆盖,一块矩形草坪,中心处有一些喷水装置,装置坐标为xi,喷水半径为ri,求最少几个装置可以全部覆盖草坪,求出每个装置能覆盖的矩形,问题转化为最少区间覆盖问题,按区间左端点排序,保存下当前能覆盖到的最远点,从左端点在最远点的左边的区间中选择右端点最大的装置,然后更新最远点。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=18800
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3+10;
struct Node{
double l,r;
bool operator < (const Node &rhs) const {
if(l == rhs.l) return r < rhs.r;
return l < rhs.l;
}
};
int main()
{
int n,l,w;
while(scanf("%d%d%d",&n,&l,&w)==3) {
vector<Node> v;
for(int i = 0; i < n; ++i) {
double a,r;scanf("%lf%lf",&a,&r);
if(r <= w/2.0) continue;
double d = sqrt(r*r-(w+0.0)*(w+0.0)/4);
double L = a-d,R = a+d;
v.push_back((Node){L,R});
}
sort(v.begin(),v.end());
double pos = 0,t = 0;
int ans = 0;
for(unsigned i = 0; i < v.size(); ++i) {
if(v[i].l <= pos) t = max(t,v[i].r); ///左端点在pos之前,用右端点跟下一次的最远点
else { ///更新最远点
pos = t;
++ans;
if(v[i].l > pos) break;
--i;
}
if(t >= l) { ///已经全部覆盖了
pos = t;
++ans;
break;
}
}
if(pos < l) ans = -1;
printf("%d\n",ans);
}
return 0;
}
UVA10905 给出n个正整数,连接成最大的整数。因为位数一样所以直接按照字典序比较就行。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=19323
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e2+10;
string s[maxn];
bool cmp(const string &a,const string &b)
{
string t1 = a+b,t2 = b+a; ///直接拼接之后判断字典序,避免复杂的讨论
return t1 > t2;
}
int main()
{
int n;
while(cin>>n) {
if(n==0) return 0;
for(int i = 0; i < n; ++i) cin>> s[i];
sort(s,s+n,cmp);
for(int i = 0; i < n; ++i) cout<<s[i];
cout<<endl;
}
return 0;
}
UVALIVE 4254 二份之后优先队列贪心,n个任务,第i个要在[ri,di]内执行,工作量为wi,问处理器的速度至少为多少工作量才能执行完所有任务。先二份处理器速度v,问题转化为能否在速度v下执行完所有任务,按时间片给处理器分配任务(这也是操作系统所采用的算法),在第t秒开始的时候将ri等于t的任务加入队列中,取出队列中截止时间最早的任务,如果截止时间小于t,说明当前速度不可能执行完毕,否则将这个任务的工作量减去v,重新加入队列,速度减去工作量,当速度为0时进入下一秒。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=11136
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10000 + 10;
struct Node{
int l,r,w;
bool operator < (const Node &rhs) const{
return r > rhs.r;
}
}a[maxn];
bool check(int v,int tot) ///抢占式处理,结束的早的优先处理
{
priority_queue<Node> Q;
int idx = 0;
for(int t = 1; t <= 20000; ++t) {
while(idx < tot && a[idx].l < t) Q.push(a[idx++]);///可以在时刻t处理一次的任务加入队列
int lft = v;///这1s内能处理的工作量
while(lft && !Q.empty()) {
Node tmp = Q.top();Q.pop();
if(tmp.r < t) return false;///存在结束时间小于t的还没
if(tmp.w > lft) {
tmp.w -= lft;
lft = 0;
Q.push(tmp);
}else {
lft -= tmp.w;
}
}
}
return Q.empty();
}
bool cmp(const Node &a,const Node &b){return a.l < b.l;}
int main()
{
int T;scanf("%d",&T);
while(T--) {
int n;scanf("%d",&n);
int tot = 0;
int low = 0, high = 1e7+20;
for(int i = 0; i < n; ++i) {
int L,R,w;
scanf("%d%d%d",&L,&R,&w);
a[tot++] = (Node){L,R,w};
}
sort(a,a+tot,cmp);
while(low < high) {
int mid = (low+high)>>1;
if(check(mid,tot)) high = mid;
else low = mid+1;
}
printf("%d\n",low);
}
return 0;
}
UVA 11134 优先队列贪心,N×N的格子上放n个车,第i个车必须在矩形i的范围里,求一种可行的方案,行和列相互独立,先处理出第i行应该放那个车,然后处理第i列应该放那个车,在确定第i行的时候选择矩形行范围包括第i行的,且结束的行下界结束的最早的那个矩形对应的车,和上一个题类似的道理,确定行的时候也是如此。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=19552
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5000 + 10;
struct Node{
int s,e;
}x[maxn],y[maxn],row[maxn],ans[maxn];
int id[maxn],tid[maxn];
bool cmpx1(const int &i, const int &j)
{
return x[i].s < x[j].s;
}
struct cmpx2{
bool operator () (const int &i,const int &j) const {
return x[j].e < x[i].e;
}
};
bool cmpy1(const int &i, const int &j)
{
return row[i].s < row[j].s;
}
struct cmpy2{
bool operator () (const int &i, const int &j) const {
return row[j].e < row[i].e;
}
};
void setid(int n)
{
for(int i = 1; i <= n; ++i) id[i] = i;
}
bool solve(int n)
{
setid(n);
sort(id+1,id+n+1,cmpx1);
int cur = 1;
priority_queue<int,vector<int>,cmpx2> Q1;
for(int i = 1; i <= n; ++i) {
while(cur <= n && x[id[cur]].s <= i) Q1.push(id[cur++]);
if(Q1.empty()||x[Q1.top()].e < i) return false;
int t = Q1.top();Q1.pop();
row[i] = y[t];
tid[i] = t;
ans[t].s = i;
}
setid(n);
sort(id+1,id+n+1,cmpy1);
cur = 1;
priority_queue<int,vector<int>,cmpy2> Q2;
for(int i = 1; i <= n; ++i) {
while(cur <= n && row[id[cur]].s <= i) Q2.push(id[cur++]);
if(Q2.empty()||row[Q2.top()].e < i) return false;
int t = Q2.top();Q2.pop();
ans[tid[t]].e = i;
}
return true;
}
int main()
{
int n;
while(scanf("%d",&n)==1&&n) {
for(int i = 1; i <= n; ++i) {
scanf("%d%d%d%d",&x[i].s,&y[i].s,&x[i].e,&y[i].e);
}
if(!solve(n)) puts("IMPOSSIBLE");
else {
for(int i = 1; i <= n; ++i) printf("%d %d\n",ans[i].s,ans[i].e);
}
}
return 0;
}
UVA 11100 鸽巢原理,n个包,每个容量为ai,容量大的可以装一个容量小的包装进去(相同的装不下),求最少几个包可以装下所有包,输出需要多少个包和每个包里装的包,答案为定义cnt(i)为容量为i的包的个数,则答案就是cnt值最大的,记为k,按照容量排序,每隔k个包放在一起,不难发现一定不会有容量相同的包在一个集合里,若选择的小于k,则一定会有容量相同的在一个集合里(鸽巢原理)。而且k个包的个数是接近平均数的,所以包数最大的那个包的个数使可行解中最优的。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=19518
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10000 + 10;
int a[maxn];
int main()
{
int n;
bool flag = 1;
while(scanf("%d",&n)==1&&n) {
for(int i = 0; i < n; ++i) scanf("%d",a+i);
sort(a,a+n);
int k = 1,cnt = 1;
for(int i = 1; i <= n; ++i) {
if(i==n||a[i]!=a[i-1]) {
k = max(k,cnt);
if(a[i]!=a[i-1])cnt = 0;
}
++cnt;
}
if(flag) flag = 0;
else puts("");
printf("%d\n",k);
for(int i = 0; i < k; ++i) {
for(int j = i; j < n; j += k) printf("%d%c",a[j]," \n"[j+k>=n]);
}
}
return 0;
}
UVALIVE 4725,二分,一个机场有W和E两个通道,只有一个跑道,每秒可以从跑道起飞一架飞机,告诉你每个时刻进入两个通道的飞机数,求通道最小的可能容量,二分容量,判断能否在容量不超过v的情况下让飞机进入通道,递推i时刻开始时(此时i时刻的飞机还没进入)能从W,E,和跑道飞走的飞机数。判断的时候看时刻i需要从W和E飞走的飞机数是否大于能从W和E飞走的飞机数,还需判断和是否大于能从跑道飞走的飞机数。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=11607
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10000 + 10;
int a[maxn],b[maxn],lx[maxn],ly[maxn],lf[maxn];
bool check(int k,int n)
{
int x = 0, y = 0,Mx = 0,My = 0;
for(int i = 1; i <= n; ++i) {
x = a[i];
y = b[i];
int lft = lf[i];
Mx = max(Mx,x-k);
My = max(My,y-k);
if(Mx + My > lft || lx[i] < Mx || ly[i] < My) return false;
}
return true;
}
int main()
{
int n,T;
scanf("%d",&T);
while(T--) {
scanf("%d",&n);
a[0] = b[0] = 0;
lx[0] = ly[0] = 0;
lf[0] = 0;
int sa = 0,sb = 0,su = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d%d",a+i,b+i);
lx[i] = lx[i-1] + (sa > lx[i-1]); ///能从a通道飞走的飞机
ly[i] = ly[i-1] + (sb > ly[i-1]); ///能从b通道飞走的飞机
lf[i] = lf[i-1] + (su > lf[i-1]); ///能从跑道飞走的飞机
sa += a[i];
sb += b[i];
su += (a[i]+b[i]);
}
for(int i = 1; i <= n; ++i) {
a[i] += a[i-1];
b[i] += b[i-1];
}
int L = 1, R = 2e5;
while(L < R) {
int mid = (L+R)>>1;
if(check(mid,n)) R = mid;
else L = mid+1;
}
printf("%d\n",L-1);
}
return 0;
}
UVALIVE 4850 不理解,先放着,有n个服务需要安装,第i个需要si的时间安装,若安装完成时间ti晚于di,则惩罚值为di-ti,求惩罚值最大的两个服务的和的最小值。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=11732
#include <bits/stdc++.h>
const int maxn = 500+10;
using namespace std;
struct Node{
int last,ed;
bool operator < (const Node & rhs) const {
if(ed == rhs.ed) return last < rhs.last;
return ed < rhs.ed;
}
}a[maxn];
bool Modify(int *m,int add)
{
if(add > m[0]) {
m[0] = add;
if(m[0] > m[1]) swap(m[0],m[1]);
return true;
}
return false;
}
int check(int x,int pos) ///尝试让x最后安装
{
int curTime = 0;
int m[2] = {0,0};
for(int i = 0; i <= pos; ++i) {
if(i == x) continue;
curTime += a[i].last;
int add = max(0,curTime-a[i].ed);
Modify(m,add);
}
curTime += a[x].last;
int add = max(0,curTime-a[x].ed);
Modify(m,add);
return m[0]+m[1];
}
int main()
{
int T;scanf("%d",&T);
while(T--) {
int n;scanf("%d",&n);
for(int i = 0; i < n; ++i) {
scanf("%d%d",&a[i].last,&a[i].ed);
}
sort(a,a+n);
int curTime = 0,m[2] = {0,0},pos = 0;
for(int i = 0; i < n; ++i) {
curTime += a[i].last;
int add = max(0,curTime-a[i].ed);
if(Modify(m,add)) pos = i;
}
int ans = 2e9;
for(int i = 0; i < n; ++i) ans = min(ans,check(i,pos));
printf("%d\n",ans);
}
return 0;
}
UVALIVE 3266 田忌赛马,双指针扫描一下,给出田忌和齐王n匹马的速度,每次选择一匹马和齐王的马比赛,输了负100,赢了加100,平局不变,求田忌最多能得多少分,排序之后双指针扫描下。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=9442
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000 + 10;
int a[maxn],b[maxn];
int main()
{
int n;
while(scanf("%d",&n)==1&&n) {
for(int i = 0; i < n; ++i) scanf("%d",a+i);
for(int i = 0; i < n; ++i) scanf("%d",b+i);
sort(a,a+n);
sort(b,b+n);
int x = 0,y = 0,ex = n,ey = n,ans = 0;
while(x < ex) {
if(a[x] > b[y]) { ///能赢直接走
++ans;
++x;
++y;
}else if(a[ex-1] > b[ey-1]) { ///能赢直接走
++ans;
--ex;
--ey;
}else {
if(a[x] < b[ey-1]) --ans;///否则用最差的和最好的比
++x;
--ey;
}
}
printf("%d\n",ans*200);
}
return 0;
}
UVA 11389,排序之后贪心,最小的和最大的匹配,n个司机,n个午间和n个夜间路线,给每个司机安排一个午间和夜间路线,使得每个路线恰好被分配到一个司机,如果一个司机的工作时间ti大于d,则会收取(t-d)×r的加班费,输出总的最小加班费。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=19807
#include <bits/stdc++.h>
const int maxn = 1e2+10;
int a[maxn],b[maxn];
using namespace std;
int solve(int n,int d)
{
int ans = 0;
for(int i = 0; i < n; ++i) {
ans += max(0,a[i]+b[i]-d);
}
return ans;
}
int main()
{
int n,d,r;
while(scanf("%d%d%d",&n,&d,&r)==3) {
if(n==0)return 0;
for(int i = 0; i < n; ++i) scanf("%d",a+i);
for(int i = 0; i < n; ++i) scanf("%d",b+i);
sort(a,a+n);
for(int i = 0; i < n; ++i) {
for(int j = i+1; j < n; ++j) {
int t1 = solve(n,d);
swap(b[i],b[j]);
int t2 = solve(n,d);
if(t1 < t2) swap(b[i],b[j]);
}
}
int ans = solve(n,d);
printf("%d\n",ans*r);
}
return 0;
}
UVALIVE 4636,逻辑推理,用一些等大的立方体搭积木,每个立方体或者直接放在网格或者立方体的上面,给出正视图每一列的高度,侧视图每一行的高度,问最少需要多少个立方体,思路若a[r][c]高度为h,且从侧视图看第r行和从正视图看第c列高度也为h,显然只需要在a[r][c]处放h个积木,第r和和第c列都能得到满足,于是我们可以n×m枚举,那些格子可以同事满足r和c,不能满足的我们就需要放两个,具体位置不用考虑。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=11518
#include <bits/stdc++.h> const int maxn = 1e2+10; int h[maxn],w[maxn]; using namespace std; int main() { int n,m; while(scanf("%d%d",&n,&m)==2&&(n+m)) { int ans = 0; for(int i = 1; i <= n; ++i) { scanf("%d",h+i);ans+=h[i]; } for(int i = 1; i <= m; ++i) { scanf("%d",w+i);ans+=w[i]; } for(int i = 1; i <= n; ++i) { for(int j = 1; j <= m; ++j) { if(h[i] == w[j]) { ans -= w[j]; w[j] = 0; break; } } } printf("%d\n",ans); } return 0; }
UVALIVE 2757 优先队列贪心,n个商品,第i件商品在di之前出售可以获得pi的价值,出售1件商品需要1s,求最大价值,倒着枚举时间,将结束时间不晚于枚举时间的加入队列里,选择队列里价值最大的出售。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=8933
#include <bits/stdc++.h> const int maxn = 1e4+10; using namespace std; struct Node{ int p,d; bool operator < (const Node & rhs) const { return p < rhs.p; } }a[maxn]; bool cmp(const Node & a,const Node &b) { return a.d > b.d; } int solve(int n) { sort(a,a+n,cmp); int cur = 0,ans = 0; priority_queue<Node>Q; for(int t = a[0].d; t >= 0; --t) { while(cur < n && a[cur].d > t) Q.push(a[cur++]);///t时刻可以选择出售的商品 while(!Q.empty()) { Node tmp = Q.top();Q.pop(); if(tmp.d <= t)continue; ans += tmp.p; break; } } return ans; } int main() { int n; while(scanf("%d",&n)==1) { for(int i = 0; i < n; ++i) { scanf("%d%d",&a[i].p,&a[i].d); } printf("%d\n",solve(n)); } return 0; }
UVALIVE 3507 优先队列贪心,n个炼钢订单,每个订单描述为(qi,di)qi表示要qi吨刚,完成时间不得晚于di,每单位时间能生产1吨刚,问最多能满足多少个订单,先按di排序订单,记录当前时间,先把当前时间加上qi,然后将qi加入队列。如果当前时间大于di,则从队列中删去q最大的那个订单,从当前时间中减去q,直到当前时间不大于di。最终队列的大小就是答案。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=9683
#include <bits/stdc++.h> const int maxn = 8e5+10; using namespace std; struct Node{ int p,d; bool operator < (const Node & rhs) const { return d < rhs.d; } }a[maxn]; int solve(int n) { priority_queue<int>Q; sort(a,a+n); int t = 0; for(int i = 0; i < n; ++i) { Q.push(a[i].p); t += a[i].p; while(t > a[i].d) { t -= Q.top(); Q.pop(); } } return Q.size(); } int main() { int T,n;scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i = 0; i < n; ++i) { scanf("%d%d",&a[i].p,&a[i].d); } printf("%d\n",solve(n)); if(T)puts(""); } return 0; }UVALIVE 4324 水模拟,给出屏幕上的窗口信息,按字典序输出顶层窗口的id。只需要判断窗口的帧是否没被覆盖,窗口内部是否无其他窗口。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=11206
#include <bits/stdc++.h> const int maxn = 1e2+10; using namespace std; char s[maxn][maxn]; bool vis[maxn][maxn]; int cnt[300]; bool check(int x,int y) { if(vis[x][y]) return false; vis[x][y] = 1; char c = s[x][y]; if(c < 'A'||c > 'Z') return false; int w = 1,h = 1; int tot = 0; while(s[x+w][y]==c) { vis[x+w][y] = 1; ++tot; ++w; } while(s[x][y+h]==c) { vis[x][y+h] = 1; ++tot; ++h; } if(w < 3||h < 3)return false; x += w-1; y += h-1; int tw = w,th = h; if(s[x][y]!=c) return false; while(h>0&&s[x][y-h+1]==c) { vis[x][y-h+1] = 1; ++tot; --h; } while(w>0&&s[x-w+1][y]==c) { vis[x-w+1][y] = 1; ++tot; --w; } if(w+h==0&&tot == cnt[c+0]+2) { x -= tw-1; y -= th-1; for(int i = 1; i + 1< tw; ++i) { for(int j = 1; j + 1 < th; ++j) { if(s[x+i][y+j]!='.') return false; } } } return true; } string solve(int n,int m) { memset(vis,0,sizeof vis); string ans; for(int i = 0; i < n; ++i) { for(int j = 0; j < m; ++j) { if(check(i,j))ans += s[i][j]; } } sort(&ans[0],&ans[0]+ans.size()); return ans; } int main() { int n,m; while(scanf("%d%d",&n,&m)==2&&(n+m)) { memset(s,0,sizeof s); memset(cnt,0,sizeof cnt); for(int i = 0; i < n; ++i) { scanf("%s",s[i]); for(int j = 0; j < m; ++j) ++cnt[s[i][j]+0]; } string ans = solve(n,m); cout<<ans<<endl; } return 0; }
UVALIVE 4328,Jhon要去参加n个婚礼仪式,第i个婚礼仪式在[si,ti]里举行,在第i个婚礼的时间必须超过婚礼的一半,为是否所有的婚礼都能满足条件,按照婚礼的中间时间排序,记录当前时间,若当前时间大于等于中点时间,则无法满足,否则更新当前时间。
http://acm.bnu.edu.cn/v3/problem_show.php?pid=11210
#include <bits/stdc++.h> const int maxn = 1e5+10; using namespace std; struct Node{ int l,r,mid; bool operator < (const Node & rhs) const { if(mid == rhs.mid) return l > rhs.l; return mid < rhs.mid; } }a[maxn]; bool solve(int n) { sort(a,a+n); int curTime = 0; for(int i = 0; i < n; ++i) { if(curTime >= a[i].mid) return false; curTime = max(curTime,a[i].l); curTime += a[i].mid - a[i].l; } return true; } int main() { int n; while(scanf("%d",&n)==1&&n) { for(int i = 0; i < n; ++i) { scanf("%d%d",&a[i].l,&a[i].r); a[i].mid = (a[i].l+a[i].r)>>1; } puts(solve(n)?"YES":"NO"); } return 0; }未能AC题目UVA 11627,LA4094 (题意没懂)