【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; }
总之这场很水。