NOIP 2017 模拟
10 30
T1:
题目:
——正解思路:
先把所有人升序排列,然后从大到小找到第一个满足 v[ i ] - v[ i - 1 ] > k 的地方,那么 i , i + 1 ....... N 都有可能获胜。
——我的乱搞:
**没有乱搞,但题目表意很容易被理解错,差点被样例阴到。。。。
——tips:
做题时要瞪大双眼,,,
满载悲伤的代码:
#pragma GCC optimize("O3")
#include <fstream>
#include <algorithm>
using std::sort;
int v[100010];
inline void read (int &x) {
x = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
}
int main () {
int t, n, k, ans;
read (t);
while (t--) {
read (n);
read (k);
for (int i = 1; i <= n; i++) read (v[i]);
sort (v + 1, v + 1 + n);
v[n + 1] = v[n];
ans = 0;
for (int i = n; v[i + 1] <= v[i] + k and i >= 1; --i, ++ans);
printf ("%d\n", ans);
}
return 0;
}
T2:
题目:
——正解思路:
我们可以考虑 DP,dp[ i ][ j ] 表示已经拿走了 i 只鳕鱼,上一次拿走了 j 只鳕鱼,按照最优策略最终会比另一个人多拿多少。
s ( l , r ) 表示 l 到 r 只鱼的重量和。(可以前缀和优化)
dp ( i , j ) = max ( s ( j + 1 , i + j ) - dp ( i + j , j ) , s ( j + 1 , i + j + 1 ) - dp ( i + j + 1 , j + 1 ) )
复杂度 O ( N ^ 2 ) 。
我们显然可以注意到,第二位肯定不超过 N ^ 0.5,所以复杂度降到 O( N ^ 1.5 )
——我的乱搞:
本来想着打一个30分的暴力,,但莫名其妙的WA了,还WA的很远,,,,,这就很监介了,,,,
——tips:
本来想不出正解就已经很悲伤了,,,然后暴力还炸了。。。。蛤蛤蛤蛤。。。
怎么办,我也很绝望啊啊啊。
满载悲伤的代码:
#pragma GCC optimize("O3")
#include <iostream>
#include <fstream>
#include <cstring>
#define maxx(x, y) x < y ? x = y : 0
using namespace std;
int a[20020], r[20020] = {0, 1};
int f[20020][205];
inline void read (int &x) {
x = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
}
int main () {
for (int i = 1; i < 20010; i++)
for (int j = 1; j <= r[i] and i + j < 20010; j++) {
r[i + j] = max (r[i + j], j);
r[i + j + 1] = max (r[i + j + 1], j + 1);
}
int t, n;
read (t);
while (t--) {
read (n);
for (int i = 1; i <= n; i++) read (a[i]), a[i] += a[i - 1];
memset (f, 0, sizeof(f));
for (int i = n; i >= 1; i--)
for (int j = min (n + 1 - i, r[i]); j >= 1; j--) {
f[i][j] = ~ (1 << 30);
if (i + j <= n + 1) maxx (f[i][j], a[i + j - 1] - a[i - 1] - f[i + j][j]);
if (i + j <= n) maxx (f[i][j], a[i + j] - a[i - 1] - f[i + j + 1][j + 1]);
}
std::cout<<f[1][1]<<'\n';
}
return 0;
}
uses math;
var
t, n, i, j : longint;
a, r : array [0..20010] of longint;
f : array [0..20010, 0..202] of longint;
begin
r[1] := 1;
for i := 1 to 20005 do begin
j := 1;
while (j <= r[i]) and (i + j < 20005) do begin
r[i + j] := max (r[i + j], j);
r[i + j + 1] := max (r[i + j + 1], j + 1);
inc (j);
end;
end;
read (t);
while t > 0 do begin
dec (t);
read (n);
for i := 1 to n do begin
read (a[i]);
inc (a[i], a[i - 1]);
end;
fillchar (f, sizeof(f), 0);
for i := n downto 1 do begin
for j := min (n + 1 - i, r[i]) downto 1 do begin
f[i, j] := not (1 shl 30);
if i + j <= n + 1 then
if f[i, j] < a[i + j - 1] - a[i - 1] - f[i + j, j] then
f[i, j] := a[i + j - 1] - a[i - 1] - f[i + j, j];
if i + j <= n then
if f[i, j] < a[i + j] - a[i - 1] - f[i + j + 1, j + 1] then
f[i, j] := a[i + j] - a[i - 1] - f[i + j + 1, j + 1];
end;
end;
writeln (f[1, 1]);
end;
end.
T3:
题目:
——正解思路:
原题等价于求一条边在多少个三元环里面,对于一个含有轻点的三元环,会被轻点统计,所以对于一条边两个点都是重点,枚举另一个重点并检查是否构成环。
复杂度 O ( M ^ 1.5 )
——我的乱搞:
本来写了一个目测 N * M 的暴力,结果其实差不多接近正解,但被 vector 卡T了。。。。。。。
——tips:
感觉不会再爱 vector 了。。。。
乖乖用数组吧。。。。。。。。
满载悲伤的代码:
#pragma GCC optimize("O3")
#include <iostream>
#include <fstream>
#include <cstring>
int t, n, m, x, y, cnt, tri, pos;
long long ans;
int to[400040], next[400040], first[100010], in[100010], v[5000];
bool b[100010];
inline void read (int &x) {
x = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
}
inline void add (int x, int y) {
to[++cnt] = y;
next[cnt] = first[x];
first[x] = cnt;
++in[x];
}
int main () {
read (t);
while (t--) {
read (n);
read (m);
ans = cnt = 0;
memset (to, 0, sizeof(to));
memset (in, 0, sizeof(in));
memset (next, 0, sizeof(next));
memset (first, 0, sizeof(first));
for (int i = 1; i <= m; i++) {
read (x);
read (y);
add (x, y);
add (y, x);
}
for (int i = 1; i <= n; i++) if (in[i] >= 3) {
memset (b, 0, sizeof(b));
pos = 0;
for (int j = first[i]; j; j = next[j]) {
b[to[j]] = true;
if (to[j] > i and in[to[j]] >= 3) v[++pos] = to[j];
}
for (int j = pos; j >= 1; j--) {
tri = 0;
for (int k = first[v[j]]; k; k = next[k]) if (b[to[k]]) ++tri;
ans += 1ll * tri * (tri - 1) / 2;
}
}
std::cout<<ans<<'\n';
}
return 0;
}