2020.09.04考試解題報告
總結
預計得分:\(50+10+0\)
實際得分:\(40+10+0\)
\(T1\) 顯然是個找規律題,我想到了要先擺成最大的正六邊形,然後再圍起來,但是不知道圍的時候該怎麼圍,於是就只寫了 \(50\) 分的做法,不過因為數數不好又丟分了。
\(T2\) 大家都在想圖,我啥也沒想出來,就一直模擬、貪心,死活過不了樣例,所以就只寫了 \(f_i=i\) 的 \(10\) 分
\(T3\) 最後半個小時想用 \(string\) 函式艹一波來著,但是不知道為什麼報錯了
如果再細心一點過一百是沒問題的……(也就這個數了)
思路
T1 方
前 \(40\%\),即 \(N\le 20\) 的資料可以直接手算。
當 \(N=6\times\dfrac{k(k+1)}{2}+1(k\in\N)\) 時,發現剛好圍成六邊形,輸出六邊形外側的周長即可。
考慮將小方格擺成能擺成的最大的正六邊形,然後處理剩下的部分,將其擺在外側。
如果六邊形有 \(x\) 層,那麼下一層的數的個數就有 \(6\times x\) 個。手推發現接下來 \(x-1\) 個數的答案相同,也就是正六邊形向外擴充套件的六條邊中的第一條邊。
接下來 \(x\)、\(x\)、\(x\)、\(x\) 個數的答案也是各自相同的,分別對應新的四條邊。
再接下來擴充套件的外層還剩 \(x+1\) 個數,這 \(x+1\) 個數的答案也是相同的。
所以特判六次,如果當前數小於 \(n\),那麼就每次增加如上所說的數。
T2
此題的建模是一個基環內向樹(或者森林)。
先咕了。
大概就是找出每個點能夠獲得的最大收益,優先使用這個收益,並將獲得最大收益的點向自己連邊。
順便記錄一下次大收益,最後在環上肯定有取不到的點,將收益減去最大收益和次大收益的差值即可。
特判出現自環的情況,如果 \(mx_x!=x\) 則可以繼續搜尋。
T3
正解:
考慮一個字串,它的所有元素會在後面的操作中逐漸分離,但是它們的相對順序是不變的。
而且它原來相鄰的兩個元素在後面的操作之後,兩個元素之間的空間可以轉化成個子問題。如果可行,則這個子問題也必定可行。
先考慮普通的 \(\text{DP}\)
轉移有兩種: 一種是從\(f_{l,r - 1,k- 1}\) 轉移過來,條件是 \(s[j] = p[k]\),就是加上一個零散的元素。
另一種是從\(f_{l,j,k}\ and\ f_{j,r,0}\) 就是在後面拼一個合法的。
然而這樣會 \(\text{TLE}\)。
緊接著我們發現,實際上,\(k=(r-l+ 1) mod len\)
所以就可以省去一維,然後就可以 \(\text{AC}\) 了。
程式碼
T1
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n;
int a[22] = {0, 6, 8, 9, 10, 11, 12, 12, 13, 14, 14};
signed main() {
n = read();
if (n <= 7) return cout << a[n] << '\n', 0;
n--;
int now = 1;
while ((now + 1) * (now + 2) * 3 <= n) now++;
if (now * (now + 1) * 3 == n) return cout << (now + 1) * 6 << '\n', 0;
int ans = (now + 1) * 6;
int cnt = now * (now + 1) * 3 + 1;
n++, now++;
//先判再加
if (cnt < n) ans++, cnt += now - 1;
if (cnt < n) ans++, cnt += now;
if (cnt < n) ans++, cnt += now;
if (cnt < n) ans++, cnt += now;
if (cnt < n) ans++, cnt += now;
if (cnt < n) ans++, cnt += now + 1;
cout << ans << '\n', 0;
return 0;
}
T2
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
long long ans;
int n, cnt, tot, mn;
struct node { int to, nxt; } e[A];
int mx[A], smx[A], val[A], vis[A];
int f[A], c[A], d[A], a[A], head[A];
inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = cnt;
}
void dfs(int x) {
if (vis[x] == cnt) return ans -= mn, void();
if (vis[x]) return;
vis[x] = cnt, mn = min(mn, val[mx[x]] - val[smx[x]]);
if (mx[x] != x) dfs(mx[x]);
}
int main() {
n = read();
for (int i = 1; i <= n; i++)
f[i] = read(), c[i] = read(), d[i] = read(), a[i] = read();
for (int i = 1; i <= n; i++) {
val[i] = d[f[i]] - c[i];
if (val[i] < 0) continue;
if (val[i] > val[mx[f[i]]]) smx[f[i]] = mx[f[i]], mx[f[i]] = i;
//待確認是>還是>=
else if (val[i] > val[smx[f[i]]]) smx[f[i]] = i;
}
for (int i = 1; i <= n; i++) ans += 1ll * a[i] * val[mx[i]];
for (int i = 1; i <= n; i++) if (mx[i]) add(mx[i], i);
for (int i = 1; i <= n; i++) if (!vis[i]) ++cnt, mn = inf, dfs(i);
cout << ans << '\n';
return 0;
}
T3
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define ll long long
#define M
using namespace std;
int read() {
int nm = 0, f = 1;
char c = getchar();
for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
return nm * f;
}
char s[301];
char s2[301];
char s4[301];
int note[33];
int note2[33];
bool f = false;
bool dp[220][220];
bool check(int len1, int len2) {
for(int i = 1; i <= len1; i++) dp[i][i - 1] = true;
for(int len = 1; len <= len1; len++) {
for(int i = 1; i + len - 1 <= len1; i++) {
int l = i;
int r = i + len - 1;
dp[l][r] = false;
int op = (len - 1) % len2 + 1;
if(dp[l][r - 1] && s2[op] == s[r - 1]) dp[l][r] = true;
else
for(int k = 1; k * len2 <= len; k++) {
if(dp[l][r - k * len2] && dp[r - k * len2 + 1][r]) dp[l][r] = true;
}
}
}
return dp[1][len1];
}
int main() {
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
int t = read();
while(t--) {
scanf("%s", s);
memset(s2, 0, sizeof(s2));
memset(s4, 0, sizeof(s4));
memset(note, 0, sizeof(note));
int len = strlen(s);
for(int i = 0; i < len; i++) note[s[i] - 'a']++;
f = false;
for(int j = 1; j <= len / 2; j++) {
if(f) break;
if(len % j != 0) continue;
for(int i = 0; i + j - 1 < len; i++) {
int l = i, r = i + j - 1;
for(int k = l; k <= r; k++) note2[s[k] - 'a']++;
int op = 0, flag = 1;
for(int k = 0; k <= 25; k++) {
if(!flag) break;
if(note[k] != 0 && note2[k] == 0) {
flag = false;
break;
}
if(note[k] == 0 && note2[k] == 0) continue;
if(op == 0) op = note[k] / note2[k];
else if(note[k] / note2[k] != op) flag = 0;
}
for(int k = l; k <= r; k++) note2[s[k] - 'a']--;
if(flag) {
for(int k = l; k <= r; k++) s2[k - l + 1] = s[k];
if(check(len, j)) {
f = true;
bool potato = false;
for(int k = l; k <= r; k++) s4[k - l] = s[k];
break;
}
}
}
}
if(!f) printf("%s\n", s);
else {
for(int i = 0; s4[i] >= 'a' && s4[i] <= 'z'; i++) putchar(s4[i]);
cout << "\n";
}
}
return 0;
}