WAhaha_hnu (zoj 2010 oct月赛)
官方解题报告 http://blog.watashi.ws/1515/zojmonthly1010/
A题 签到题,╮(╯▽╰)╭,因为 int -> char* 错了一次,还是很粗心。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<string> using namespace std; const int N = 101100; char str[N]; bool isch( char ch ){ if( (ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z') ) return true; return false; } string get_str( int x ){ string tmp; char sa[1010]; int len = 0; while( x ){ sa[len++] = x%10 + '0'; x /= 10; } for(int i = len-1; i >= 0; i-- ) tmp += sa[i]; return tmp; } int main(){ while( gets( str) ){ if( strcmp( str, "EOF" ) == 0 ) break; //printf("str = %s", str ); int len = strlen(str), n = 0, i = 0; string s; while( i < len ) { if( isch( str[i] ) ){ s += str[i]; int t = i+1; while( isch(str[t]) && (t<len) ) ++t; t--; if( t-i >= 1 ){ if( t-i >= 2 ) s += get_str( t-i-1 ); s += str[t]; } i = t+1; } else s += str[i++]; } printf("%s\n", s.c_str() ); } return 0; }
B题 一开始理解错题意,粗心一路到底啊~~
假设横切为x,纵切为y,克隆为a, 则对于总分数n,以及操作次数m,共有
2*x*(y+1) + a = n
x + y + a = m
两式联立可得 x, y 的计算式, 因为 n,m 都比较大, 但是 x*y <= n => x <= sqrt(n) || y <= sqrt(n)
所以我们可以通过分别枚举 x,y 到sqrt(n) 来得出结果, 因为 x,y对称,所以可以在一个循环内得出。
另外,以上两式的成立条件是在 x > 0 的前提下, 所以当 x = 0,时候要特判,还有当 n <= m 时也要特判。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<stdlib.h> #include<math.h> #define MIN(a,b) (a)<(b)?(a):(b) typedef long long LL; int main(){ int n, m, T; scanf("%d", &T); while( T-- ) { scanf("%d %d", &n,&m); if( n <= m ){ printf("-1\n"); continue; } if( n-1 == m ){ printf("0\n"); continue; } bool flag = false; int res = m+1; int Max = sqrt(n)+1; for(int x = 0; x <= Max; x++ ) { int ta = n-m-x, tb = 2*x-1; if( ta%tb == 0 ){ int y = ta/tb; if( (y>=0) && (x+y<=m) ){ flag = true; res = MIN( res, m-x-y ); } } ta = n-m+x; tb = 2*x+1; if( ta%tb == 0 ){ int y = ta/tb; if( (y >=0) && (x+y<=m) ){ flag = true; res = MIN( res, m-x-y); } } } if( flag ) printf("%d\n", res ); else printf("-1\n"); } return 0; }
E题 看题后第一眼想到DP, 但是时间复杂度无法承受,然后就没管了,回头细想下,觉得贪心应该还是能过的... 越学越笨了~~~
题目未限定通过陷阱顺序, 通过将陷阱按照 D 排序后, 依次处理,若累积时间 T <= Di 则拆除过去,否则失血,此时选择 [1,i]区间
中时间消耗最大的,这里使用优先队列 来维护。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int N = 25010; pair<int,int> p[N]; int n, k; int main(){ while( scanf("%d%d", &n,&k) != EOF) { for(int i = 0; i < n; i++) scanf("%d%d", &p[i].second,&p[i].first ); sort( p, p+n ); int T = 0, hp = 0; priority_queue< int > Q; for(int i = 0; i < n; i++ ){ T += p[i].second; Q.push( p[i].second ); while( T > p[i].first ){ T -= Q.top(); Q.pop(); hp++; } } if( hp < k ) printf("%d\n", hp ); else printf("-1\n"); } return 0; }
I题 ╮(╯▽╰)╭,比赛时看题能力还是不够,错把题目看成是 折现上的点 相邻的直接距离了。
计算折线总长度后,得到点间距离,然后从起点开始模拟查找就可以得出结果了。