2020.9.4 解题报告

2020.9.4


\[\text{打原作,疮个吐,原曲自然就记住。} \]

\[\text{By:TouhouMusicBlock} \]


答题情况

总成绩 : 140 , 排名 : 2 / 6
T1 : 100 T2 : 10 T3 : 30

各题目分析

题目 1 :
预估成绩 : 100 实际成绩 : 100 考试用时 : 8:00 ~ 10:00

找规律题,不会做,最后暴力枚举过去了。

题目 2 :
预估成绩 : 100 实际成绩 : 10 考试用时 : 10:00 ~ 11:10

想到了与标算非常相似的算法,但是对题意的理解不清,导致挂分。

题目 3 :
预估成绩 : 20 实际成绩 : 40 考试用时 : 11:10 ~ 11:30

一开始就觉得不可做,弃了。
最后没时间了,写了暴力。


题目解析

T1

找规律,考虑家庭的构造方式。
正解的构造方法是从 \(n=1\) 的情况不断在外面进行包围。
即尽量围成一个正六边形,之后把剩余的在外面围起来。
模拟即可。


考场上的构造:
找到一条最长的连续家庭,之后向上/下进行扩展,扩展的长度每次减 1。
如果可以同时扩展则扩展,否则只扩展一边。
最后构造出一个正六边形削去上下顶的样子。
需要预处理一下正六边形的大小,来找到最小的合法的 最长连续家庭的长度。

不知道正确性,但是过大样例了。


T2

考虑 \(i\)\(f_i\) 连边,转化为图论问题。
仅有 \(n\) 条边,得到的图一定是一个基环内向树构成的森林。
考虑一个基环内向树。

先考虑环大小为 1 的情况,即出现自环。
可看做只有根自己连向自己,实质上是一棵普通的树。
发现从叶向上按按钮,仅有叶节点不能买到,其他的均可以买完。
对于一个树点,如果要买到它,应选择花费最小的儿子按下按钮。
答案可以 \(O(n)\) 遍历获得。

考虑断环后,套用上述做法。
对于一个节点,若其有多个儿子,且多个儿子价格不同,选择价格较高的边断掉。
若没有这样的情况,钦定环上环边 - 树边贡献最小的点断开环边。
每个点儿子中收益最大/次大的儿子,即可知道贡献之差。


T3

考虑在原串 \(S\)\(O(n^2)\) 枚举答案串 \(p\),检查原串是否可以通过插入答案串得到。
发现对于某时刻插入的答案串,在插入其他串后,各字符的相对顺序不变。
考虑 DP 检查。

\(f_{l,r,k} = \text{true or false}\) 表示,原串的子串 \([l,r]\),取出一个子序列构成答案串的前缀 \(1\sim k\) 后,是否可以通过答案串插入构成。

根据状态,可以得到一些信息:
\(f_{l,r,k} = \text{true}\),子串 \([l,r]\),取出一个子序列构成答案串的前缀 \(1\sim k\) 后,长度一定是答案串的倍数。
若子串 \([l,r]\) 中存在多个不重合的子序列,为答案串的前缀,则一定不合法。
若答案串合法,则 \(f_{1,n,\operatorname{len}(p)} = \text{true}\)

显然有两种转移:

  1. \(f_{l,r+1,k+1} = f_{l,r+1,k+1} \lor f_{l,r,k} (S_{r+1}=p_{k+1})\),表示在 \([l,r]\) 后接上一个字符。
  2. \(f_{l,r,k} = f_{l,r,k} \lor f_{l,l+t\times \operatorname{len}(p),0} (l + t\times \operatorname{len}(p) \le r)\),表示在 \([l,r]\) 后接上一个 可以通过答案串插入构成的串。

最后判断 \(f_{1,n,\operatorname{len}(p)} = \text{true}\) 是否成立。


代码实现

T1 :

考场代码

//
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#define ll long long
const int kMaxn = 1e5 + 10;
//=============================================================
ll sum1[kMaxn], sum2[kMaxn];
//=============================================================
inline ll read() {
  ll f = 1, w = 0;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar())
    if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void GetMax(int &fir_, int sec_) {
  if (sec_ > fir_) fir_ = sec_;
}
void GetMin(int &fir_, int sec_) {
  if (sec_ < fir_) fir_ = sec_;
}
//=============================================================
int main() {
  freopen("square.in", "r", stdin);
  freopen("square.out", "w", stdout);
  
  for (int i = 1; i < kMaxn; ++ i) {
    sum1[i] = sum1[i - 1] + 1ll * i; 
  }
  for (int i = 1; i < kMaxn; ++ i) {
    sum2[i] = 1ll * i * i;
  }
  
  ll n = read(), ans;
  int i = 1;
  while (sum2[i] < n) ++ i;
  
  for (ll j = i; j; ++ j) {
    ll nowans = 0, sum = 0;
    sum = j;
    ll k, cnt;
    for (k = sum, cnt = 0; sum < n;) {
       -- k, ++ cnt;
      sum += 2ll * k;
    }
    nowans = 2 * (k + 1)+ 4ll * (cnt + 1ll) - 2ll;
    if (n <= sum - k) nowans --;
    if (i == j) ans = nowans;
    if (j > i + 10 && nowans > ans) break;
    if (nowans < ans) ans = nowans;
  }
  printf("%lld", ans);
  return 0;
}

T2:

考场代码

//
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#define ll long long
const int kMaxn = 2e5 + 10;
//=============================================================
struct Edge {
  int u, v, ne;
} e[kMaxn << 1];
int n, m, edge_num, head[kMaxn], f[kMaxn], c[kMaxn], d[kMaxn];
int dfn_num, bel_num, dfn[kMaxn], low[kMaxn], bel[kMaxn], size[kMaxn];
ll a[kMaxn], val[kMaxn], minval[kMaxn], sumval[kMaxn];
int out[kMaxn];
std :: stack <int> st;
//=============================================================
inline int read() {
  int f = 1, w = 0;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar())
    if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void GetMax(int &fir_, int sec_) {
  if (sec_ > fir_) fir_ = sec_;
}
void GetMin(int &fir_, int sec_) {
  if (sec_ < fir_) fir_ = sec_;
}
void AddEdge(int u_, int v_) {
  e[++ edge_num].u = u_, e[edge_num].v = v_;
  e[edge_num].ne = head[u_], head[u_] = edge_num;
}
void Tarjan(int u_) {
  dfn[u_] = low[u_] = ++ dfn_num;  
  st.push(u_);
  for (int i = head[u_]; i; i = e[i].ne) {
    int v_ = e[i].v;
    if (! dfn[v_]) {
      Tarjan(v_);
      GetMin(low[u_], low[v_]);
    } else if (! bel[v_]) {
      GetMin(low[u_], dfn[v_]);
    }
  }
  if (low[u_] == dfn[u_]) {
    ++ bel_num;
    for (int r = u_ + 1; r != u_; st.pop()) {
      r = st.top();
      bel[r] = bel_num;
      if(val[r] < minval[bel_num]) {
        minval[bel_num] = val[r];
      }
      sumval[bel_num] += 1ll * a[r] * val[r];
      size[bel_num] ++;
    }
  }
}
void Topsort() {
  ll ans = 0ll;
  for (int i = 1; i <= bel_num; ++ i) {
    if (! out[i]) {
      if (size[i] == 1) continue ;
      ans += 1ll * sumval[i] - 1ll * minval[i];
    } else {
      ans += 1ll * sumval[i];
    }
  }
  printf("%lld", ans);
}
void koishi() {
  int satori;
}
//=============================================================
int main() {
  freopen("dundundun.in", "r", stdin);
  freopen("dundundun.out", "w", stdout);
  n = read();
  memset(minval, 127, sizeof (minval));
  for (int u = 1, lim = n; u <= lim; ++ u) {
    f[u] = read(), c[u] = read(), d[u] = read();
    a[u] = read();
    if (u == f[u]) {
      AddEdge(u, ++ n);
      AddEdge(n, f[u]);
      koishi();
      a[n] = 1ll;
    } else {
      AddEdge(u, f[u]); 
    }
  }
  for (int i = 1; i <= n; ++ i) {
    val[i] = d[f[i]] - c[i];
  }
  for (int i = 1; i <= n; ++ i) {
    if (! dfn[i]) Tarjan(i);
  }
  edge_num = 0;
  memset(head, 0, sizeof (head));
  for (int i = 1; e[i].v; ++ i) {
    int u = e[i].u, v = e[i].v;
    if (bel[u] != bel[v]) {
      out[bel[u]] ++;
      AddEdge(bel[u], bel[v]);
    }
  }
  Topsort();
  return 0;
}
/*
7
2 1 6 1
3 1 2 3
6 1 5 2
5 1 2 2
5 1 5 10
6 1 5 2
4 1 4 3
539343565151
*/ 

正解

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define ll long long
using namespace std;
const int N=100005;
int n,idx,mn,f[N],c[N],d[N],w[N],a[N],mx[N],secmx[N],dfn[N];
long long ans;

void dfs(int x) {
	if(dfn[x]==idx) {
		ans-=mn;
		return;
	}
	if(dfn[x]) return;
	dfn[x]=idx;
	if(mx[x]) {
		ans+=1LL*w[mx[x]]*a[x];
		mn=std::min(mn,w[mx[x]]-w[secmx[x]]);
		if(mx[x]^x) dfs(mx[x]);
	}
}
int main() {
		freopen("dundundun.in","r",stdin); freopen("dundundun.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d%d%d%d",&f[i],&c[i],&d[i],&a[i]);
	for(int i=1;i<=n;++i) {
		w[i]=d[f[i]]-c[i];
		if(w[i]<0) continue;
		if(w[i]>w[mx[f[i]]]) {
			secmx[f[i]]=mx[f[i]];
			mx[f[i]]=i;
		} else if(w[i]>w[secmx[f[i]]]) {
			secmx[f[i]]=i;
		}
	}
	for(int i=1;i<=n;++i) if(!dfn[i]) mn=(1<<30),idx++,dfs(i);
	printf("%lld\n",ans);
	return 0;
}

T3:

考场代码

//
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <unordered_map>
#define ll long long
//=============================================================
std :: string S;
int n;
std :: unordered_map <std :: string, bool> vis;
//=============================================================
inline int read() {
  int f = 1, w = 0;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar())
    if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void GetMax(int &fir_, int sec_) {
  if (sec_ > fir_) fir_ = sec_;
}
void GetMin(int &fir_, int sec_) {
  if (sec_ < fir_) fir_ = sec_;
}
bool Check(std :: string p) {
//  std :: cout << p << "\n";
  bool ret = true;
  int n1 = p.length(), n2 = n;
  std :: string tmp = S;
  
//  std :: cout << tmp << "\n";
  
  for (int i = 1; i <= n / n1; ++ i) {
    int pos = tmp.find(p);
//    printf("%d\n", pos);
    if (pos == - 1) return false;
    std :: string tmptmp;
    for (int j = 0; j < pos; ++ j) tmptmp.push_back(tmp[j]);
    for (int j = pos + n1; j < n2; ++ j) tmptmp.push_back(tmp[j]);
    n2 -= n1;
    tmp = tmptmp;
  }
  return ret;
}
//=============================================================
int main() {
  freopen("string.in", "r", stdin);
  freopen("string.out", "w", stdout);
  int T = read();
  while (T --) {
    int anslth = 11451419;
    std :: string ans;
    std :: cin >> S;
    n = S.length();
    vis.clear();
    for (int lth = 1; lth <= n; ++ lth) {
      if (anslth < lth) break;
      if (n % lth) continue ;
      for (int l = 0; l < n; ++ l) {
        int r = l + lth - 1;
        if (r >= n) break;
        std :: string tmp;
        for (int i = l; i <= r; ++ i) tmp.push_back(S[i]);
        if (vis.count(tmp)) continue ;
        vis[tmp] = true;
        if (Check(tmp)) {
          if (! ans.length()) ans = tmp;
          if (tmp < ans) ans = tmp;
          anslth = lth;
        }
      }
    }
    std :: cout << ans << "\n";
  }
  return 0;
}
/*
2
ababab
aaaaabaacdacabab
*/ 

正解

#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 17:22  Luckyblock  阅读(184)  评论(1编辑  收藏  举报