[NOIP2014 提高組] 題解
阿新 • • 發佈:2021-08-13
一個下午做了個 530.. 沒寫過數論題所以 D2T3 暴力了個 30, 話說 AHOI 的時候也是忘記取膜 100 -> 20.. 為什麼連同餘都不會awa
也只有 14 年的提高組有會做的.. 最難的也不過藍題+ \({\ }\) 反正我弱弱(
話說這不就是普及組摸你題(
難道我普及 400 都沒有嗎 哭哭
D1T1 P1328 [NOIP2014 提高組] 生活大爆炸版石頭剪刀布
打表模擬即可. 這都不會還是去打普及組吧.
#include <stdio.h> const int score[5][5] = { { 0, 0, 1, 1, 0 }, { 1, 0, 0, 1, 0 }, { 0, 1, 0, 0, 1 }, { 0, 0, 1, 0, 1 }, { 1, 1, 0, 0, 0 } }; int n, n1, n2; int a[203], b[203]; int main () { scanf("%d %d %d", &n, &n1, &n2); for (int i = 0; i < n1; i++) scanf("%d", &a[i]); for (int i = 0; i < n2; i++) scanf("%d", &b[i]); int ans1 = 0, ans2 = 0; for (int i = 0; i < n; i++) { ans1 += score[a[i % n1]][b[i % n2]]; ans2 += score[b[i % n2]][a[i % n1]]; } printf("%d %d\n", ans1, ans2); return 0; }
D1T2 P1351 [NOIP2014 提高組] 聯合權值
wqy 巨佬的 blog 講的很清楚! 和我的想法完全相同. 去看看!!
認真讀題仔細想想就行, 或者像我一樣摸你賽時先打暴力然後數學推公式也能想出來! 多試試就行了(
核心公式:
\(2a_1a_2+2a_1a_3+...+2a_{n-1}*a_n = (a_1+a_2+...+a_n)^2 - (a_1^2+a_2^2+...+a_n^2)\)
#include <stdio.h> #include <vector> #include <algorithm> #define ci const int & int n; int a[200003]; std:: vector <int> g[200003]; int ans1 = 0, ans2 = 0; inline void add_edge (ci x, ci y) { g[x].push_back(y); return; } int main() { scanf("%d", &n); for (int i = 1; i < n; i++) { int x, y; scanf("%d %d", &x, &y); add_edge(x, y); add_edge(y, x); } for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= n; i++) { int max1 = 0, max2 = 0, sum = 0, msum = 0; for (int j = 0; j < g[i].size(); j++) { int x = a[g[i][j]]; if (x > max1) max2 = max1, max1 = x; else if (x > max2) max2 = x; sum = (sum + x) % 10007; msum = (msum + x * x) % 10007; } ans1 = std:: max(ans1, max1 * max2); if (g[i].size() >= 2) ans2 = (ans2 + sum * sum - msum) % 10007; } printf("%d %d\n", ans1, ans2); return 0; }
D1T3 P1941 [NOIP2014 提高組] 飛揚的小鳥
很好的一道 DP 題, 轉化為揹包就行了(
#include <stdio.h> #include <algorithm> int n, m, q; int x[10003], y[10003]; int low[10003], high[10003]; // 區間 [low[i],high[i]] 可以通過 bool iswall[10003]; int d[10003][1003]; int main() { scanf("%d %d %d", &n, &m, &q); for (int i = 1; i <= n; i++) low[i] = 1, high[i] = m; for (int i = 1; i <= n; i++) for (int j = 0; j <= m; j++) d[i][j] = 0x3F3F3F3F; d[0][0] = 0x3F3F3F3F; for (int i = 0; i < n; i++) scanf("%d %d", &x[i], &y[i]); for (int i = 1; i <= q; i++) { int a, b, c; scanf("%d %d %d", &a, &b, &c); low[a] = b + 1; high[a] = c - 1; iswall[a] = true; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) if (j - x[i - 1] >= 0) { d[i][j] = std:: min(d[i][j], d[i - 1][j - x[i - 1]] + 1); d[i][j] = std:: min(d[i][j], d[i][j - x[i - 1]] + 1); } for (int k = m - x[i - 1]; k <= m; k++) { d[i][m] = std:: min(d[i][m], d[i - 1][k] + 1); d[i][m] = std:: min(d[i][m], d[i][k] + 1); } for (int j = low[i]; j <= high[i]; j++) if (j + y[i - 1] <= m) d[i][j] = std:: min(d[i][j], d[i - 1][j + y[i - 1]]); for (int j = 1; j <= m; j++) if (!(low[i] <= j && j <= high[i])) d[i][j] = 0x3F3F3F3F; } int ans1 = 0, ans2 = 0x3F3F3F3F; for (int j = 1; j <= m; j++) if (d[n][j] < ans2) ans2 = d[n][j], ans1 = 1; if (ans1 == 0) { ans2 = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) if (d[i][j] != 0x3F3F3F3F && iswall[i]) { ans2++; break; } } printf("%d\n%d\n", ans1, ans2); return 0; }
D2T1 P2038 [NOIP2014 提高組] 無線網路發射器選址
列舉每個點能否成為最大答案, 時間複雜度 \(O(n^4)\)
雖然用上二維字首和會更快 不過這樣就能過了(
#include <stdio.h>
#include <algorithm>
int d, k, n = 128, m = 128;
int a[203][203];
int ans1 = 0, ans2 = 0;
int main() {
scanf("%d %d", &d, &k);
for (int i = 1; i <= k; i++) {
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
a[x][y] = z;
}
for (register int i = 0; i <= n; i++) {
for (register int j = 0; j <= m; j++) {
register int sum = 0;
for (register int x = std:: max(0, i - d); x <= std:: min(n, i + d); x++)
for (register int y = std:: max(0, j - d); y <= std:: min(m, j + d); y++)
sum += a[x][y];
if (sum == ans2)
ans1++;
else if (sum > ans2) {
ans2 = sum;
ans1 = 1;
}
}
}
printf("%d %d\n", ans1, ans2);
return 0;
}
D2T2 P2296 [NOIP2014 提高組] 尋找道路
挺簡單的吧..
- 反向建邊, 從終點開始 dfs 看哪些點能到達終點
- 列舉每個點的每個子節點看這個點是否滿足
出邊所指向的點都直接或間接與終點連通
- 用最短路, 跳過不滿足題意的節點
#include <stdio.h>
#include <vector>
#include <queue>
#define ci const int &
struct NODE {
int p, val;
inline const bool operator < (const NODE &rhs) const {
return val > rhs.val;
}
} nd;
int n, m;
int s, t;
std:: vector <int> g[2][10003];
int d[10003];
bool vis[10003];
bool cvis[10003]; // 出邊所指向的點都直接或間接與終點連通的點
bool ccvis[10003]; // 與終點相連的點
inline void add_edge (ci x, ci y, ci p) {
if (x == y) // 自環
return;
for (int i = 0; i < g[p][x].size(); i++)
if (g[p][x][i] == y) // 重邊
return;
g[p][x].push_back(y);
return;
}
void dfs1 (int cur) { // 從終點出發, 看哪些點能夠到達終點
ccvis[cur] = true;
for (int i = 0; i < g[1][cur].size(); i++)
if (!ccvis[g[1][cur][i]])
dfs1(g[1][cur][i]);
return;
}
inline void djs (int cur) { // 最短路
for (int i = 1; i <= n; i++)
d[i] = 0x3F3F3F3F;
std:: priority_queue <NODE> pq;
nd.p = cur, nd.val = 0;
pq.push(nd);
d[cur] = 0;
while (!pq.empty()) {
nd = pq.top(); pq.pop();
int x = nd.p, val = nd.val;
vis[x] = true;
for (int i = 0; i < g[0][x].size(); i++) {
int fw = g[0][x][i];
if (!vis[fw] && cvis[fw] && d[fw] > val + 1) {
d[fw] = val + 1;
nd.p = fw, nd.val = d[fw]; pq.push(nd);
}
}
}
return;
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d %d", &x, &y);
add_edge(x, y, 0);
add_edge(y, x, 1);
}
scanf("%d %d", &s, &t);
dfs1(t);
for (int i = 1; i <= n; i++) {
cvis[i] = true;
if (ccvis[i] == false)
cvis[i] = false;
for (int j = 0; j < g[0][i].size(); j++)
if (ccvis[g[0][i][j]] == false)
cvis[i] = false;
}
djs(s);
printf("%d\n", d[t] == 0x3F3F3F3F ? -1 : d[t]);
return 0;
}
D2T3 P2312 [NOIP2014 提高組] 解方程
30 分暴力應該比較好拿 用上快速冪時間複雜度為 \(O(mn\log{n})\) 再加上優化只要輸入的數較小就能拿 80+ (應該能優化到 100)
然後我就不會了
看了眼題解發現對所有數進行取膜就行了, 輸入的時候像快讀一樣再加上取膜就行了
順便有個 秦九韶公式 可以把時間複雜度降低為 \(O(mn)\)
建議膜上 \(1e9+7\), 至於為什麼自己 google
#include <stdio.h>
#include <ctype.h>
#define ll long long
const ll MODN = 1e9 + 7;
int n, m;
ll a[103];
int ans = 0, anss[1000003];
char ch;
inline ll scan () {
ll x = 0ll, f = 1ll;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-')
f = -1ll;
ch = getchar();
}
while (isdigit(ch)) {
x = ((x << 1) % MODN + (x << 3) % MODN + ch - '0') % MODN;
ch = getchar();
}
return x * f;
}
int main() {
scanf("%d %d\n", &n, &m);
for (int i = 0; i <= n; i++)
a[i] = scan();
for (register ll i = 1ll; i <= m; i++) {
ll sum = 0ll;
for (register int j = n; j >= 1; j--)
sum = (sum + a[j]) * i % MODN;
sum = (sum + a[0]) % MODN;
if (sum == 0ll)
anss[++ans] = i;
}
printf("%d\n", ans);
for (int i = 1; i <= ans; i++)
printf("%d\n", anss[i]);
return 0;
}
嚶嚶嚶 為什麼一上考場就裂開 這和現在普及組水平應該差不多吧(
對了取膜那個膜不是打錯了