1. 程式人生 > 實用技巧 >2020.09.04考試解題報告

2020.09.04考試解題報告

總結

預計得分:\(50+10+0\)

實際得分:\(40+10+0\)

\(T1\) 顯然是個找規律題,我想到了要先擺成最大的正六邊形,然後再圍起來,但是不知道圍的時候該怎麼圍,於是就只寫了 \(50\) 分的做法,不過因為數數不好又丟分了。

\(T2\) 大家都在想圖,我啥也沒想出來,就一直模擬、貪心,死活過不了樣例,所以就只寫了 \(f_i=i\)\(10\)

\(T3\) 最後半個小時想用 \(string\) 函式艹一波來著,但是不知道為什麼報錯了

如果再細心一點過一百是沒問題的……(也就這個數了)



思路

T1 方

here

\(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

here

此題的建模是一個基環內向樹(或者森林)。

先咕了。

大概就是找出每個點能夠獲得的最大收益,優先使用這個收益,並將獲得最大收益的點向自己連邊。

順便記錄一下次大收益,最後在環上肯定有取不到的點,將收益減去最大收益和次大收益的差值即可。

特判出現自環的情況,如果 \(mx_x!=x\) 則可以繼續搜尋。


T3

here

正解:

考慮一個字串,它的所有元素會在後面的操作中逐漸分離,但是它們的相對順序是不變的。
而且它原來相鄰的兩個元素在後面的操作之後,兩個元素之間的空間可以轉化成個子問題。如果可行,則這個子問題也必定可行。
先考慮普通的 \(\text{DP}\)

思路: \(f_{l,r,k}\) 表示區間 \([l,r]\) 中, 有零散的 \(k\) 個字母拼起來等於\(p_{1\sim k}\),其它的都合法,是否可行。
轉移有兩種: 一種是從\(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;
}