A.http://acm.hdu.edu.cn/showproblem.php?pid=5538
求表面积,只需要将所有的1*1的小块扫描一遍。将每一个块与他相邻四周进行比较,如果该快高度大,则将该快高度减去周围块高度然后累加。复杂度O(nm)
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cmath> #include<algorithm> typedef long long LL; const double EPS = 1e-8; const double PI = acos(-1.0); using namespace std; const int MAXN = 55; int n, m; int a[MAXN][MAXN]; int dir[4][2] = { { 0, 1 }, { 0, -1 }, { -1, 0 }, { 1, 0 } }; int main(){ int T, i, j, k; scanf("%d\n", &T); while (T--){ memset(a, 0, sizeof(a)); int ans = 0; scanf("%d%d", &n, &m); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++){ scanf("%d", &a[i][j]); if (a[i][j] > 0) ans++; } for (i = 1; i <= n; i++) for (j = 1; j <= m; j++){ for (k = 0; k < 4; k++){ int x = i + dir[k][0]; int y = j + dir[k][1]; if (a[x][y] < a[i][j]){ ans += a[i][j] - a[x][y]; } } } printf("%lld\n", ans); } return 0; }
2.http://acm.hdu.edu.cn/showproblem.php?pid=5532
原来序列要么按照升序,要么按照降序去判断,首先可以假定原序列是升序(降序同样来处理).首先将原序列从左到右扫描一遍,不断的比较相邻的两个元素,直到遇到某两元素满足
a[i]>a[i+1]或者扫描到末尾时逃出。若扫描到了末尾,则原序列是增序列,满足条件。若是遇到a[i]>a[i+1]跳出,则我们可以断定,我们要删去的元素一定是a[i]或者a[i+1],可以这样来想,如果删去的是其它元素,则该序列中还是存在a[i]和a[i+1]破坏来递增性。于是问题简单了,只需要分别去掉a[i],和a[i+1]来判断一下原序列是否是递增序列即可。同样的,当假设原序列是递减序列时,处理方法相同。
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cmath> #include<algorithm> typedef long long LL; const double EPS = 1e-8; const double PI = acos(-1.0); using namespace std; const int MAXN =1000001; int a[MAXN]; int n; bool UpSroted(){ int i; for (i = 0; i < n - 1; i++) if (a[i]>a[i + 1]) //若遇到降序的则跳出 break; if (i>=n - 2) //a[i+1]后面没有数了 return true; int j = i + 2; while (j < n - 1){ if (a[j]>a[j + 1]) break; j++; } if (j<n - 1) //再次出现不符合 return false; if (a[i] <= a[i + 2]) //去掉a[i+1]即可 return true; if (a[i + 1]>a[i + 2]) return false; if (i == 0) return true; if (a[i - 1] <= a[i + 1]) return true; return false; } bool DownSroted(){ int i; for (i = 0; i < n - 1; i++) if (a[i]<a[i + 1]) //若遇到降序的则跳出 break; if (i >= n - 2) //a[i+1]后面没有数了 return true; int j = i + 2; while (j < n - 1){ if (a[j]<a[j + 1]) break; j++; } if (j<n - 1) //再次出现不符合 return false; if (a[i] >= a[i + 2]) //去掉a[i+1]即可 return true; if (a[i + 1]<a[i + 2]) return false; if (i == 0) return true; if (a[i - 1] >= a[i + 1]) return true; return false; } int main(){ int T, i; scanf("%d\n", &T); while (T--){ scanf("%d", &n); for (i = 0; i < n; i++) scanf("%d", &a[i]); bool flag = UpSroted() || DownSroted(); if (flag) printf("YES\n"); else printf("NO\n"); } return 0; }
3.http://acm.hdu.edu.cn/showproblem.php?pid=5533
原问题给出的都是整数点,这样以来就只有正方形符合要求了,只需要判断一下给定的是否是4个点,这四个点是否可以构成正方形。
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cmath> #include<algorithm> using namespace std; const double PI = acos(-1.0); const int N = 300; const double EPS = 1e-8;//实数精度 //点结构类型 struct Point{ double x, y; Point(double a = 0, double b = 0){ x = a; y = b; } }; Point operator-(Point a, Point b){ return Point(a.x - b.x, a.y - b.y); } //重载==,判断点a,b是否相等 bool operator==(Point a, Point b){ return abs(a.x - b.x) < EPS&&abs(a.y - b.y) < EPS; } //比较实数r1与r2的大小关系 int RlCmp(double r1, double r2 = 0){ if (abs(r1 - r2) < EPS) return 0; return r1>r2 ? 1 : -1; } double Dot(Point p1, Point p2, Point p3, Point p4){ Point a = p2 - p1; Point b = p4 - p3; return a.x*b.x + a.y*b.y; } //检查以p1p2和p3p4为对角线是否可以构成正方形 bool firstCheck(Point p1, Point p2, Point p3, Point p4){ Point mid0 = Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2); Point mid1 = Point((p3.x + p4.x) / 2, (p3.y + p4.y) / 2); if (!(mid0 == mid1)) //如果中点不重合 return false; return RlCmp(Dot(p1, p2, p3, p4)) == 0; //对角线垂直 } bool isSqual(Point P[]){ return firstCheck(P[0], P[1], P[2], P[3]) || firstCheck(P[0], P[2], P[1], P[3]) || firstCheck(P[0], P[3], P[1], P[2]); } int main(){ Point P[N]; int T,i,n; double x, y; scanf("%d", &T); while (T--){ scanf("%d", &n); for (i = 0; i < n; i++){ scanf("%lf%lf", &x, &y); P[i] = Point(x, y); } if (n != 4){ printf("NO\n"); continue; } if (isSqual(P)) printf("YES\n"); else printf("NO\n"); } return 0; }
4.http://acm.hdu.edu.cn/showproblem.php?pid=5536
该问题是贪心+字典树。虽然网上有O(n^3)爆力剪枝可以过,表示不会。将每一个数字的二进制从高位到低位存入到字典树中形成01串。这时候我们需要一个节点变量v,每次插入只需要将v++.接下来,枚举a[i],a[j](j>i),首先在字典树中删掉a[i]和a[j],删除做法很简单,将对应节点位置v--即可,然后用a[i]+a[j]在字典树中进行01串的匹配,匹配完后再插入a[i],a[j]准备下一次的匹配。匹配方法采用贪心思想,依次从高位向低位匹配,若当前数该位为1则去优先匹配0,若没有0匹配,则只能匹配1了。当前位置是0,则优先去匹配1,当没有1匹配,就只能匹配0了。如此下去,直到匹配到最后一位。这样有一个问题,每一个数二进制串长度不一样,给匹配带来不便,做法是,将所有的串高位补0,使得长度为32位。这样就可开心的匹配了。
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<algorithm> typedef long long LL; const int MAXN = 1000+10; using namespace std; struct TrieNode{ TrieNode(){ memset(next, 0, sizeof(next)); v = 0; } TrieNode* next[2]; LL v; }; LL MAX; TrieNode *root; void Insert(LL x){ TrieNode*p = root; MAX = 1; MAX <<= 32; for (LL i =MAX; i >0; i>>=1){ LL id =(i&x)>0; if (p->next[id] == NULL) p->next[id] = new TrieNode; p = p->next[id]; p->v++; } } void Delete(LL x){ TrieNode*p = root; MAX = 1; MAX <<= 32; for (LL i = MAX; i >0; i >>= 1){ LL id = (i&x)>0; p = p->next[id]; p->v--; } } LL getMAX(LL x){ TrieNode *p = root; MAX = 1; MAX <<= 32; LL rt,ans=x,i=-1; for (LL i = MAX; i >0;i>>=1){ LL id = (x&i)>0; if (p->next[id ^ 1] && p->next[id ^ 1]->v > 0){ if ((id == 0)) //说明x当前位为0,即将变为1 ans +=i ; p = p->next[id ^ 1]; continue; } if (id) //如果x当前位置为1,则即将要变为0 ans -= i; p = p->next[id]; } return ans; } void Free(TrieNode*T){ if (T){ for (int i = 0; i < 2; i++) Free(T->next[i]); free(T); T = NULL; } } LL a[MAXN]; int main(){ LL n,i,j,T; scanf("%I64d", &T); while (T--){ root = new TrieNode; scanf("%I64d", &n); for (i = 0; i < n; i++){ scanf("%I64d", &a[i]); Insert(a[i]); } LL ans =0; for (i = 0; i < n; i++){ Delete(a[i]); for (j = i + 1; j < n; j++){ Delete(a[j]); ans = max(ans, getMAX(a[i] + a[j])); Insert(a[j]); } Insert(a[i]); } printf("%I64d\n",ans); Free(root); } return 0; }
。。。。待更新