NOIP 2017 模拟 :
----10.17
T1 : chair
题目 :
******************************************************************************************************************
******************************************************************************************************************
*****************************************************和谐********************************************************
******************************************************************************************************************
******************************************************************************************************************
数据范围 :
95% : n <= 10000;
100% : n <= 100000; 1 <= x <= 100; 1 <= a, c < 24; 0 <= b, d < 60.
——正解思路 :
枚举时间, 差分, 求个前缀和;
——我的乱搞 :
排序, 枚举每个人, 求最大值.
——正解代码 :
#pragma GCC optimize("O3")
#include<cstdio>
int a[1441];
inline int read() {
int i=0;
char c=getchar();
while(c<'0' or c>'9') c=getchar();
while(c>='0' and c<='9') i = (i << 3) + (i << 1) + c - 48, c = getchar();
return i;
}
int main()
{
int n,x,h,m,ans=0;
n=read();
while(n--) {
x=read();
h=read();
m=read();
a[h*60+m]+=x;
h=read();
m=read();
a[h*60+m]-=x;
}
x=0;
for(int i=0;i<=1440;++i) {
x+=a[i];
if(x>ans) ans=x;
}
printf("%d\n",ans);
return 0;
}
T2 : sort
题目 :
******************************************************************************************************************
******************************************************************************************************************
*****************************************************和谐********************************************************
******************************************************************************************************************
******************************************************************************************************************
数据范围 :
40% : n <= 1000
70% : n <= 50000
100% : t <= 5; n <= 100000.
——正解思路 :
用双向链表把多个子串连接起来, 连接子串内的数字. 每次O(1)删除不和谐的数, 然后依次检查合并或者删除子串. 代码细节较多. 复杂度 O(n).
——我的乱搞 :
寻找降序的子串, 并合并, 然后再反复统计, 剩余子串. ...然后光荣WA .
tips :
对于一些没有太大把握的题, 在写出 疑(jue)似(dui)正(bao)解(li) 的同时, 最好还是将数据分类处理, 将小数据用暴力解决, 防止爆 0.
——正解代码 :
#pragma GCC optimize("O3")
#include <cstdio>
#include <cctype>
#include <list>
using namespace std;
list <list <int> > x;
list <list <int> > :: iterator itr, itr3;
list <int> :: iterator itr2;
inline int Read () {
int i = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) i = (i << 3) + (i << 1) + c - 48, c = getchar();
return i;
}
inline void put (int x) {
short num = 0;
char c[12];
do c[++num] = x % 10 + 48, x /= 10; while (x);
while (num) putchar(c[num--]);
}
int main () {
int t, n, v, last;
t = Read();
while (t--) {
x.clear();
n = Read();
last = -1;
list <int > now;
for (int i = 1; i <= n; i++) {
v = Read();
if (v < last) x.push_back(now), now.clear();
last = v;
now.push_back(v);
}
if (!now.empty()) x.push_back(now);
while (x.size() >= 2) {
for (itr = x.begin(); itr != x.end(); itr++) {
if (itr != x.begin()) (*itr).pop_front();
itr3 = itr;
++itr3;
if (!(*itr).empty() and itr3 != x.end()) (*itr).pop_back();
}
while (!x.empty() and x.begin() -> size() == 0) x.pop_front();
for (itr = x.begin(); itr != x.end(); itr++)
while ((++(itr3 = itr)) != x.end()) {
if ((*itr3).empty() or (*itr3).front() >= (*itr).back()) {
(*itr).splice((*itr).end(), (*itr3));
x.erase(itr3);
}
else
break;
}
}
if (!x.empty()) {
put(x.begin() -> size());
putchar ('\n');
for (itr2 = x.begin() -> begin(); itr2 != x.begin() -> end(); itr2++)
put(*itr2), putchar(' ');
}
else puts("0");
putchar('\n');
}
return 0;
}
T3 : beans
题目 :
******************************************************************************************************************
******************************************************************************************************************
*****************************************************和谐********************************************************
******************************************************************************************************************
******************************************************************************************************************
数据范围 :
30% : n <= 9;
70% : t <= 1;
100% : t <= 10; n <= 200.
——正解思路 :
区间dp, 首先由于颜色相同的色块一定是一起消除的, 所以先把连在一起的点合成一个点, 同时记录每个点的点权.
dp[ l ][ r ] 表示[ l , r ] 的球全部消除的最少次数. num[ i ]表示点 i 的点权. 转移有以下四种 :
3 - num[ l ] l == r
dp[ l ][ k ] + dp[ k + 1 ][ r ] l <= k < r
dp[ l + 1 ][ k - 1 ] + dp[ k + 1 ][ r - 1 ] color[ l ] == color[ r ] == color[ k ] and num[ l ] + num[ r ] <> 4 and num[ k ] == 1
dp[ l + 1 ][ r - 1 ] + max ( 0, 3 - num[ l ] - num[ r ])
所以我们就得到一个O( n ^ 3) 的 dp, 可以通过此题.
——我的乱搞 :
暴力枚举每种情况, 伪剪枝.
碰上较难的题......就要搞好暴力, 附某位 da lao 的A* 暴力 :
骗分骗样例, 暴力出奇迹.
——正解代码 :
var
n, t, i, j, k, cnt : integer;
ch, num : array [0..210] of integer;
dp : array [0..210, 0..210] of integer;
c : char;
s : string;
function max (a, b : integer) : integer;
begin
if a > b then exit (a)
else exit (b);
end;
function min (a, b : integer) : integer;
begin
if a < b then exit (a)
else exit (b);
end;
begin
readln (t);
while t > 0 do begin
dec (t);
fillchar (dp, sizeof (dp), $3f);
fillchar (num, sizeof (num), 0);
n := 0;
s := '';
read (c);
while (c < '0') or (c > '1') do read (c);
while (c = '0') or (c = '1') do begin
inc (n);
s := s + c;
if eoln then break;
read (c);
end;
cnt := 0;
for i := 1 to n do
if s[i] <> s[i - 1] then begin
inc (cnt);
if s[i] = '0' then ch[cnt] := 0
else ch[cnt] := 1;
num[cnt] := 1;
end
else inc (num[cnt]);
for i := cnt downto 1 do
for j := 1 to cnt do begin
if i = j then begin
dp[i][j] := 3 - num[i];
continue;
end;
if ch[i] = ch[j] then begin
dp[i][j] := dp[i + 1][j - 1] + max(0, 3 - num[i] - num[j]);
if num[i] + num[j] < 4 then begin
k := i + 2;
while k < j do begin
if num[k] = 1 then
dp[i][j] := min (dp[i][j], dp[i + 1][k - 1] + dp[k + 1][j - 1]);
inc (k, 2);
end;
end;
end;
for k := i to j - 1 do
dp[i][j] := min (dp[i][j], dp[i][k] + dp[k + 1][j]);
end;
writeln (dp[1][cnt]);
end;
end.