NOIP模拟题 2016.11.5 [贪心] [坐标离散化] [循环序列LIS]
2016-11-05 18:01
393 查看
T1:
题意:大天使之剑。。有平A、重击、群击三种攻击方式,伤害分别是1、2、1。,要让所有的小兵GG,问最少需要受多少伤害。
由于群击在人数大于等于3的时候占优势,那么这种情况优先考虑群击,小于等于2的时候重击,但是如果最小的兵只有1滴HP,就群击。
T2:
Floodfill只不过数据很大,要用坐标离散化。
如果采用横向闭区间纵向开区间的方法,可能导致恰好在端点的两个小块漏算,因为横向闭区间可能没有纵向的线段来分割最后一个格子。
所以采用重复计算的方法,都记成闭区间就好了。。
T3:
题意:每个地鼠出现有限次数t,循环出现,问LIS长度。
用链表循环,每次一个点如果没有更新d[]说明这个点以后都没有用了,delete
数据保证了n*MAX<=2e7,那么总时间复杂度不会超过这个值。
题意:大天使之剑。。有平A、重击、群击三种攻击方式,伤害分别是1、2、1。,要让所有的小兵GG,问最少需要受多少伤害。
由于群击在人数大于等于3的时候占优势,那么这种情况优先考虑群击,小于等于2的时候重击,但是如果最小的兵只有1滴HP,就群击。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<vector> #include<queue> #include<stack> #include<map> #include<set> #include<string> #include<iomanip> #include<ctime> #include<climits> #include<cctype> #include<algorithm> #ifdef WIN32 #define AUTO "%I64d" #else #define AUTO "%lld" #endif using namespace std; #define smax(x,tmp) x=max((x),(tmp)) #define smin(x,tmp) x=min((x),(tmp)) #define maxx(x1,x2,x3) max(max(x1,x2),x3) #define minn(x1,x2,x3) min(min(x1,x2),x3) typedef long long LL; const int maxn = 100005; int a[maxn]; int n,m; int main() { freopen("zhijian.in","r",stdin); freopen("zhijian.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",a+i); sort(a+1,a+n+1); LL ans = 0; int cnt = n; int cur = 1; while(true) { if(!m || cur>n || !cnt) break; if(!a[cur]) { cur++; continue; } if(cnt>=3) { int delta = min(a[cur],m); int new_dead = 0; for(int j=cur;j<=n;j++) { a[j] -= delta; if(!a[j]) new_dead++; } ans += delta*cnt - new_dead; m -= delta; cnt -= new_dead; } else if(a[cur] == 1) { int new_dead = 0; for(int j=cur;j<=n;j++) { a[j]--; if(!a[j]) new_dead++; else break; } ans += cnt - new_dead; m--; cnt -= new_dead; } else { int hit = a[cur]>>1; smin(hit,m); a[cur] -= (hit<<1); m -= hit; ans += cnt*hit - (!a[cur]); cnt -= (!a[cur]); } } if(cnt) for(int i=1;i<=n;i++) if(a[i]) ans += (LL)a[i]*cnt - 1 , cnt--; printf(AUTO,ans); return 0; }
T2:
Floodfill只不过数据很大,要用坐标离散化。
如果采用横向闭区间纵向开区间的方法,可能导致恰好在端点的两个小块漏算,因为横向闭区间可能没有纵向的线段来分割最后一个格子。
所以采用重复计算的方法,都记成闭区间就好了。。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<vector> #include<queue> #include<stack> #include<map> #include<set> #include<string> #include<iomanip> #include<ctime> #include<climits> #include<cctype> #include<algorithm> #ifdef WIN32 #define AUTO "%I64d" #else #define AUTO "%lld" #endif using namespace std; #define smax(x,tmp) x=max((x),(tmp)) #define smin(x,tmp) x=min((x),(tmp)) #define maxx(x1,x2,x3) max(max(x1,x2),x3) #define minn(x1,x2,x3) min(min(x1,x2),x3) #define Xn Xn #define Yn Yn typedef long long LL; const int maxn = 2005; struct Node { int x1,y1,x2,y2; }node[maxn]; int X[maxn],Y[maxn]; int Xn,Yn; inline void discrete(int a[],int &n) { sort(a+1,a+n+1); n = unique(a+1,a+n+1) - a - 1; } int vis[maxn][maxn]; // 2 for protected , 1 for occupied void init() { int M; scanf("%d",&M); int curx = 0, cury = 0; for(int i=1;i<=M;i++) { char ch = (char) getchar(); while(!isalpha(ch)) ch = (char) getchar(); int d; scanf("%d",&d); if(ch == 'U') { node[i].x2 = curx+1; node[i].y2 = cury+1; X[++Xn] = curx+1; Y[++Yn] = cury+1; curx -= d; node[i].x1 = curx; node[i].y1 = cury; X[++Xn] = curx; Y[++Yn] = cury; } else if(ch=='D') { node[i].x1 = curx; node[i].y1 = cury; X[++Xn] = curx; Y[++Yn] = cury; curx += d; node[i].x2 = curx+1; node[i].y2 = cury+1; X[++Xn] = curx+1; Y[++Yn] = cury+1; } else if(ch=='L') { node[i].x2 = curx+1; node[i].y2 = cury+1; X[++Xn] = curx+1; Y[++Yn] = cury+1; cury -= d; node[i].x1 = curx; node[i].y1 = cury; X[++Xn] = curx; Y[++Yn] = cury; } else { node[i].x1 = curx; node[i].y1 = cury; X[++Xn] = curx; Y[++Yn] = cury; cury += d; node[i].x2 = curx+1; node[i].y2 = cury+1; X[++Xn] = curx+1; Y[++Yn] = cury+1; } } discrete(X,Xn); discrete(Y,Yn); for(int i=1;i<=M;i++) { node[i].x1 = lower_bound(X+1,X+Xn+1,node[i].x1) - X; node[i].y1 = lower_bound(Y+1,Y+Yn+1,node[i].y1) - Y; node[i].x2 = lower_bound(X+1,X+Xn+1,node[i].x2) - X; node[i].y2 = lower_bound(Y+1,Y+Yn+1,node[i].y2) - Y; for(int x = node[i].x1;x < node[i].x2;x++) for(int y = node[i].y1;y < node[i].y2;y++) vis[x][y] = 2; // protected } } const int dx[] = {-1,0,0,1}; const int dy[] = {0,-1,1,0}; inline bool inRange(int x,int y) { return 0<=x&&x<=Xn && 0<=y&&y<=Yn; } void dfs(int x,int y) { vis[x][y] = 1; // occupied for(int k=0;k<4;k++) { int xx = x + dx[k]; int yy = y + dy[k]; if(!inRange(xx,yy) || vis[xx][yy]) continue; dfs(xx,yy); } } LL work() { LL ans = 0; for(int x=0;x<=Xn;x++) for(int y=0;y<=Yn;y++) if(vis[x][y] ^ 1) ans += (LL)(X[x+1]-X[x]) * (Y[y+1]-Y[y]); return ans; } int main() { freopen("luobo.in","r",stdin); freopen("luobo.out","w",stdout); init(); dfs(0,0); LL ans = work(); printf(AUTO,ans); return 0; }
T3:
题意:每个地鼠出现有限次数t,循环出现,问LIS长度。
用链表循环,每次一个点如果没有更新d[]说明这个点以后都没有用了,delete
数据保证了n*MAX<=2e7,那么总时间复杂度不会超过这个值。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<vector> #include<queue> #include<stack> #include<map> #include<set> #include<string> #include<iomanip> #include<ctime> #include<climits> #include<cctype> #include<algorithm> #ifdef WIN32 #define AUTO "%I64d" #else #define AUTO "%lld" #endif using namespace std; #define smax(x,tmp) x=max((x),(tmp)) #define smin(x,tmp) x=min((x),(tmp)) #define maxx(x1,x2,x3) max(max(x1,x2),x3) #define minn(x1,x2,x3) min(min(x1,x2),x3) template <class T> inline void read(T &x) { x = 0; T flag = 1; char ch = (char)getchar(); while(ch<'0' || ch>'9') { if(ch == '-') flag = -1; ch = (char)getchar(); } while(ch>='0' && ch<='9') { x = (x<<1) + (x<<3) + ch - '0'; ch = (char)getchar(); } x *= flag; } const int INF=0x3f3f3f3f; const int maxn = 100005; int n,N,t,T,cas,MAX; struct Node { int pre,suf; int val; }node[maxn]; #define pre(x) node[x].pre #define suf(x) node[x].suf #define val(x) node[x].val int _begin; inline void init() { n = N; t = T; memset(node,0,sizeof(node)); for(int i=1;i<=n;i++) { read(val(i)); pre(i) = i-1; suf(i) = i+1; } _begin=n+1; pre(1) = _begin; suf(n) = _begin; suf(_begin) = 1; pre(_begin) = n; } inline void erase(int root) { suf(pre(root)) = suf(root); pre(suf(root)) = pre(root); } vector <int> d; int dynamic() { d.clear(); int root = suf(_begin); while(true) { if(root == _begin) root=suf(root),t--; if(!t || root==_begin) break; vector <int> ::iterator it = lower_bound(d.begin(),d.end(),val(root)); if(it == d.end()) d.push_back(val(root)); else { if((*it) == val(root)) erase(root); else (*it) = val(root); } root = suf(root); } return d.size(); } int main() { freopen("dishu.in","r",stdin); freopen("dishu.out","w",stdout); scanf("%d%d%d%d",&cas,&N,&MAX,&T); while(cas--) { init(); int ans = dynamic(); printf("%d\n",ans); } return 0; }
相关文章推荐
- NOIP模拟题[贪心][离散化][LIS]
- NYOJ133子序列(坐标离散化)
- NOIP 模拟题 可接受序列
- [vijos NOIP模拟题]天神下凡 贪心+搜索
- 【贪心】NOIP模拟题“Kun”
- 【NOIP模拟题】【线段树】【离散化】【DP】2016.11.14第三题 有趣的有趣的家庭菜园 题解
- NOIP模拟题 2016.11.1 [模拟] [贪心] [杂题]
- NOIP模拟题[贪心][DP][数论]
- NOIP模拟题 2016.11.15 [LIS] [spfa] [同余最短路] [矩阵快速幂] [容斥原理] [数学]
- NOIP模拟题 2016.8.29 [树相关问题] [数论] [贪心] [拓扑排序]
- NOIP模拟题 [LIS][建图][递推][容斥]
- 【NOIP模拟题】【数学归纳法】【GCD】2016.11.16 第一题 LGTB 与序列 题解
- NOIP模拟题 2016.10.13 [贪心] [记忆化搜索]
- NOIP模拟题 [暴力][贪心][栈][dfs][找规律]
- BZOJ 1852 [MexicoOI06]最长不下降序列(贪心+DP+线段树+离散化)
- [NOIP模拟题][Catalan数][逆元][贪心][线段树][DFS][搜索顺序剪枝]
- [NOIP模拟题][杂题][贪心][水题]
- NOIP模拟题 2016.11.12 [Catalan数] [贪心] [动态规划] [DLX] [数独]
- 【NOIP 模拟题】T2(next数组|线段树+最长上升子序列)
- 【NOIP模拟题】【贪心】【动态规划DP】2016.11.12第二题题解