Forever Young

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;
}
posted @ 2020-09-04 21:57  Loceaner  阅读(164)  评论(0编辑  收藏  举报