【HDU5246(1001)】
贪心。首先对所有对手战斗力排序,然后先找出<=m的战斗力中最大的那个,如果没有<=m的战斗力那他必定不能战胜后面任何一个,然后尽量用最少的次数把自己的战斗力提升到>=max{a[i]};这样就能战胜所有人了,所以开始战力选择<=m中最大的那个,每次找到战力<=now+k(now是当前战力)中最大的值,然后必定要提升把now提升到那个值,这样最后只要能>=max{a[i]}就能感获胜;从左往右扫描一遍,再尽量往右升战力就好了,复杂度n*logn;
【AC CODE】514ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 10000+10;
LL a[MAXN], m,k;
int n;
bool sloved()
{
sort(a,a+n);
int st = -1;
rep(i,0,n)
{
if(a[i] > m)
{
st = i;
break;
}
}
if(-1 == st) return true;
if(0 == st) return false;
LL now = a[st-1]+k;
k--;
int i = st;
while(i < n)
{
int p = upper_bound(a+i,a+n,now)-a-1;
if(p < i) return false;
now = a[p]+k;
i = p+1;
if(k > 0)
k--;
else break;
}
return now+k >= a[n-1];
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int t,count = 0;
scanf("%d%*c", &t);
while(t--)
{
scanf("%d %I64d %I64d%*c", &n, &m, &k);
rep(i,0,n)
{
scanf("%I64d%*c", &a[i]);
}
printf("Case #%d:\n", ++count);
if(sloved()) puts("why am I so diao?");
else puts("madan!");
}
return 0;
}
【HDU5247(1002)】
询问的是连续的长度为k的区间;所以只要每次询问的时候扫描一边序列,进去右边的左边的出来(保持序列长度为k即可),这样就能判断所有的连续k长子串,然后关键是判断子串中的所有数是不是连续的;这个只要判断子串的满足: 最大值-最小值==子串长度&&子串不重复 就可以;对于最值直接RMQ-ST预处理,可以做到O(1)查询;然后判断不重复需要先离散值,然后数组直接O(1)判;如果用set会超时,手写的HASH都超时了,所以还是乖乖离散吧。这样总复杂度n*m
【AC CODE】280ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <map>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 10000+10, MOD = 1000007;
int a[MAXN],mx[MAXN][20], mi[MAXN][20],cnt;
map<int,int> num;
void st_init(int n)
{
repe(i,1,n) mx[i][0] = mi[i][0] = a[i];//下标从1开始的
for(int j = 1; (1<<j) <= n; j++)
{
for(int i = 1; i+(1<<j)-1 <= n; i++)//下标从1开始的
{
mx[i][j] = max(mx[i][j-1], mx[i+(1<<(j-1))][j-1]);
mi[i][j] = min(mi[i][j-1], mi[i+(1<<(j-1))][j-1]);
}
}
}
void st(int x, int y, int &mxv, int &miv)
{
int k = 0;
while((1<<(k+1)) <= y-x+1) k++;
mxv = max(mx[x][k], mx[y-(1<<k)+1][k]);
miv = min(mi[x][k], mi[y-(1<<k)+1][k]);
}
int get_id(int v)
{
if(num.find(v) == num.end())
{
num[v] = cnt++;
return cnt-1;
}
return num[v];
}
int vis[MAXN];
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int n,m;
scanf("%d %d%*c", &n, &m);
cnt = 0;
repe(i,1,n) scanf("%d%*c", &a[i]);
st_init(n);
repe(i,1,n) a[i] = get_id(a[i]);
puts("Case #1:");
while(m--)
{
int k;
scanf("%d%*c", &k);
if(k > n)
{
puts("0");
continue;
}
int ans = 0, sum = 0;
clc(vis,0);
rep(i,1,k)
{
if(!vis[a[i]]) sum++;
vis[a[i]]++;
}
repe(i,k,n)
{
int mxv,miv;
st(i-k+1,i,mxv,miv);
int tmp = mxv-miv;
if(!vis[a[i]]) sum++;
vis[a[i]]++;
if(k-1 == tmp && sum == k) ans++;
if(!--vis[a[i-k+1]]) sum--;
}
printf("%d\n", ans);
}
return 0;
}
【HDU5248(1003)】
二分答案即可,每次O(n)判断当前代价是否可行。复杂度n*logn
【AC CODE】374ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 100000+10;
int a[MAXN],n;
bool ok(int m)
{
int st = a[0]-m, mi = st+1;
rep(i,1,n)
{
if(a[i] < mi && mi-a[i] > m) return false;
if(a[i] < mi) st = mi;
else
{
st = max(mi,a[i]-m);
}
mi = st+1;
}
return true;
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int t,count = 0;
scanf("%d%*c", &t);
while(t--)
{
scanf("%d%*c", &n);
rep(i,0,n) scanf("%d%*c", &a[i]);
int ans = INF, x = 0,y = 10000000;
while(x <= y)
{
int m = (x+y)>>1;
if(ok(m)) y = m-1, ans = m;
else x = m+1;
}
printf("Case #%d:\n%d\n", ++count,ans);
}
return 0;
}
【HDU5249(1004)】
很裸的平衡树题,我用的Treap,没什么的好说的吧。复杂度n*logn
【AC CODE】 421ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 10000+10;
queue<int> q;
struct NODE{
NODE *ch[2];
int r;//随机优先级
int v;//键值
int sum;//以当前节点为根的总结点数
NODE(int a){
v = a,ch[0] = ch[1] = NULL, r = rand(), sum = 1;
}
int cmp(int x){
if(x == v) return -1;
return x<v?0:1;
}
void push_up(){
sum = 1;
if(ch[0]) sum += ch[0]->sum;
if(ch[1]) sum += ch[1]->sum;
}
};
void clear(NODE* &u)//清空树
{
if(!u) return;
if(u->ch[0]) clear(u->ch[0]);
if(u->ch[1]) clear(u->ch[1]);
delete u;
u = NULL;
}
void rotate(NODE* &u, int d)//旋转,d = 0左旋,d = 1右旋
{
NODE *k = u->ch[d^1];
u->ch[d^1] = k->ch[d], k->ch[d] = u;
u->push_up(), k->push_up(); //更新sum,先更新u
u = k;
}
void insert(NODE* &u, int v)//插入键值v(不需要保证v是否存在)
{
if(!u) u = new NODE(v);
else
{
int d = v < u->v?0:1;//不要使用cmp(),可能已经存在相同的v
insert(u->ch[d], v);
if(u->r < u->ch[d]->r) //如果儿子的r比当前大则需要旋转
rotate(u,d^1);//左儿子则右旋,右儿子左旋
}
u->push_up();//更新sum
}
void del(NODE* &u, int v)//删除键值v
{
int d = u->cmp(v);
if(~d)//没找到继续往下找
del(u->ch[d],v);
else
{
NODE *o = u;
if(u->ch[0] && u->ch[1])//左右儿子都存在
{
int d2 = u->ch[0]->r > u->ch[1]->r?1:0;//优先级大的儿子旋转为根
rotate(u,d2);
del(u->ch[d2],v);
}
else
{
if(!u->ch[0]) u = u->ch[1];//只有右儿子
else u = u->ch[0];//只有左儿子
delete o;
//u = NULL;
}
}
if(u) u->push_up();
}
int kth(NODE* u, int k)//寻找第k大键值
{
if(!u || k <= 0 || k > u->sum) return 0;//不存在
int d = k-(u->ch[0]?u->ch[0]->sum:0);
if(d == 1) return u->v;//找到第k大值
if(d <= 0) return kth(u->ch[0],k);
return kth(u->ch[1],k-(u->ch[0]?u->ch[0]->sum:0)-1);
}
void pt(NODE *u)
{
if(NULL == u) return;
pt(u->ch[0]);
printf("%d\n", u->v);
pt(u->ch[1]);
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int n,count = 0;
while(~scanf("%d%*c", &n))
{
while(!q.empty()) q.pop();
NODE *rt = NULL;
printf("Case #%d:\n",++count);
while(n--)
{
char op[21];
scanf("%s", op);
if('i' == op[0])
{
int v;
scanf("%d%*c", &v);
q.push(v);
insert(rt,v);
}
else if('o' == op[0])
{
del(rt,q.front());
q.pop();
}
else
{
int m = q.size();
int pos = floor(m/2)+1;
printf("%d\n",kth(rt,pos));
}
}
clear(rt);
}
return 0;
}
【HDU5250(1005)】
还没做;
【HDU5251(1006)】
最小矩形覆盖模版题。
【AC CODE】0ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
#define PR 1e-8
#define maxdouble 1e20
const int INF = 0x3f3f3f3f, MAXN = 1000*4+10;
struct TPoint
{
double x,y;
};
struct TPolygon
{
int n;
TPoint p[MAXN];
}ply;
double MIN(double a,double b) {return a>b?b:a;}
int dblcmp(double a)
{
if(fabs(a)<PR) return 0;
return a>0?1:-1;
}
double dist(TPoint a,TPoint b)//距离
{
double s1=a.x-b.x;
double t1=a.y-b.y;
return sqrt(s1*s1+t1*t1);
}
double cross(TPoint a,TPoint b,TPoint c)//叉积
{
double s1=b.x-a.x;
double t1=b.y-a.y;
double s2=c.x-a.x;
double t2=c.y-a.y;
return s1*t2-s2*t1;
}
double dot(TPoint a,TPoint b,TPoint c)//点积
{
double s1=b.x-a.x;
double t1=b.y-a.y;
double s2=c.x-a.x;
double t2=c.y-a.y;
return s1*s2+t1*t2;
}
bool cmop(TPoint a,TPoint b)//x、y排序
{
if(fabs(a.x-b.x)<PR) return a.y<b.y;
else return a.x<b.x;
}
bool cmp(TPoint a,TPoint b)//叉积内排序
{
int d1=dblcmp(cross(ply.p[0],a,b));
return d1>0||(d1==0&&dist(ply.p[0],a)<dist(ply.p[0],b));
}
TPolygon graham()//求凸包
{
int i,top=2;
for(i=2;i<ply.n;i++)
{
while(top>1&&(dblcmp(cross(ply.p[top-2],ply.p[i],ply.p[top-1])))>=0) top--;
ply.p[top++]=ply.p[i];
}
ply.n=top;
return ply;
}
double solve()
{
int i,p=1,q=1,r;
double minarea=maxdouble,area;
ply.p[ply.n]=ply.p[0];
for(i=0;i<ply.n;i++)
{
while(dblcmp(cross(ply.p[i],ply.p[i+1],ply.p[p+1])//最上一点
-cross(ply.p[i],ply.p[i+1],ply.p[p]))>0)
p=(p+1)%ply.n;
while(dblcmp(dot(ply.p[i],ply.p[i+1],ply.p[q+1])//最右一点
-dot(ply.p[i],ply.p[i+1],ply.p[q]))>0)
q=(q+1)%ply.n;
if(i==0) r=q;
while(dblcmp(dot(ply.p[i],ply.p[i+1],ply.p[r+1])//最左一点
-dot(ply.p[i],ply.p[i+1],ply.p[r]))<=0)
r=(r+1)%ply.n;
double d=dist(ply.p[i],ply.p[i+1])*dist(ply.p[i],ply.p[i+1]);
area=cross(ply.p[i],ply.p[i+1],ply.p[p])*//求面积
(dot(ply.p[i],ply.p[i+1],ply.p[q])-dot(ply.p[i],ply.p[i+1],ply.p[r]))/d;
minarea=MIN(area,minarea);//更新
}
return minarea;
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int t,count = 0;
scanf("%d%*c", &t);
while(t--)
{
scanf("%d",&ply.n);
ply.n *= 4;
int i;
double area;
for(i=0;i<ply.n;i++) scanf("%lf%lf",&ply.p[i].x,&ply.p[i].y);
sort(ply.p,ply.p+ply.n,cmop);//排序
sort(ply.p+1,ply.p+ply.n,cmp);
ply=graham();//凸包
if(ply.n<3) area=0;
else area=solve();
printf("Case #%d:\n%.0f\n",++count,area);
}
return 0;
}
总之这场很水。