2024.8.31校测
T1
题目描述
今天的酒席有
每个人都有一个喜爱的酒种类,每个人想要与和自己喝一样酒的人碰杯,请你设计一个方法,在保证每个人参与碰杯,且没有手臂交叉的情况下,有最多的人与喝一样酒的人碰杯,输出最多有多少人能与喝一样酒的人碰杯。
输入格式
第一行一个数
第二行
输出格式
一个整数,表示在保证每个人参与碰杯,且没有手臂交叉的情况下,最多有多少人能与喝一样酒的人碰杯。
输入样例
6
1 2 2 3 3 1
输出样例
3
数据规模
对于
对于
题解
考虑区间 DP。
设
答案很简单,就是
可以发现,如果出现下图这种情况:
那么这条线左右两边的人都无法碰杯,这样就将大问题转化为了一模一样的小问题。于是,我们可以枚举这条分割线的两个端点,就可以得到以下 DP 转移方程:
这样状态个数为
完整代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 9;
int a[N], dp[N][N], n;
bool flag;
int main(){
freopen("toasting.in", "r", stdin);
freopen("toasting.out", "w", stdout);
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int j = 2; j <= n; j++)
for(int i = j - 1; i >= 1; i -= 2)
for(int k = i; k < j; k += 2){
if(a[j] == a[k])
dp[i][j] = max(dp[i][j], dp[i][k - 1] + dp[k + 1][j - 1] + 1);
else
dp[i][j] = max(dp[i][j], dp[i][k - 1] + dp[k + 1][j - 1]);
}
printf("%d", dp[1][n]);
return 0;
}
T2
题目描述
院子里有一颗又高又大的草莓树,草莓树有 YES
,否则输出 NO
。
输入格式
第一行一个数
接下来
每组第一行一个数
接下来
输出格式
输出 YES
,否则输出 NO
输入样例
2
6
2 4
0 5
4 2
2 1
1 1
4 2
6
2 4
0 6
4 2
2 1
1 1
4 2
输出样例
YES
NO
样例解释
第一组可以切掉
数据规模
对于
对于
题解
这里给出一种简单的 DFS 做法。
首先,如果这棵树上所有苹果的营养值之和不是 NO
。
否则,就从根节点开始 DFS,同时记录以每个点为根的子树营养值的和,如果遇到一棵子树的营养值的和为总营养值的
完整代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 9;
struct Edge{
int v, nex;
} e[N << 1];
int head[N], ecnt;
void addEdge(int u, int v){
e[++ecnt] = Edge{v, head[u]};
head[u] = ecnt;
}
int T, fa[N], a[N], siz[N], n, rt, cnt, s;
void dfs(int u){
for(int i = head[u]; i; i = e[i].nex){
int v = e[i].v;
if(v == fa[u])
continue;
dfs(v);
siz[u] += siz[v];
}
if(siz[u] == s / 3){
cnt++;
siz[u] = 0;
}
}
void init(){
memset(siz, 0, sizeof(siz));
memset(head, 0, sizeof(head));
ecnt = 0;
cnt = s = 0;
}
int main(){
freopen("strawberry.in", "r", stdin);
freopen("strawberry.out", "w", stdout);
scanf("%d", &T);
while(T--){
init();
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d%d", &fa[i], &a[i]);
if(fa[i] != 0){
addEdge(i, fa[i]);
addEdge(fa[i], i);
} else
rt = i;
s += a[i];
}
for(int i = 1; i <= n; i++)
siz[i] = a[i];
if(s % 3 != 0)
printf("NO\n");
else {
dfs(rt);
if(cnt >= 2)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
T3
题目描述
有的词语常常别有深意,比如
输入格式
第一行一个数
接下来
输出格式
一共
输入样例
4
hehehe
hehe
woquxizaolehehe
woquxizaole
hehehehe
hehe
woyaoqugenbierenliaotianle
wanan
输出样例
3
2
5
1
样例解释
黑色表示取原意,红色表示取深意。
第 1 组:
第 3 组:
数据规模
对于
对于
题解
首先先用 KMP 找出模式串在文本串中的位置,设
那答案就是
我们发现,当枚举到
发现转移是一段区间和,可以用树状数组或前缀和优化成
注意,本题需要初始化
这样,状态个数为
完整代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 9, MOD = 1000000007;
int nex[N], last[N], dp[N], cnt, T, lens, lenp;
char s[N], p[N];
int pre[N], t[N];
bool flag[N];
void init(){
memset(nex, 0, sizeof(nex));
memset(last, 0, sizeof(last));
memset(dp, 0, sizeof(dp));
memset(flag, 0, sizeof(flag));
memset(pre, 0, sizeof(pre));
memset(t, 0, sizeof(t));
cnt = 0;
}
void get(){
nex[0] = nex[1] = 0;
for(int i = 1; i < lenp; i++){
int j = nex[i];
while(j && p[i] != p[j])
j = nex[j];
if(p[i] == p[j])
nex[i + 1] = j + 1;
else
nex[i + 1] = 0;
}
}
void kmp(){
int j = 0;
for(int i = 0; i < lens; i++){
while(j && s[i] != p[j])
j = nex[j];
if(s[i] == p[j])
j++;
if(j == lenp)
last[++cnt] = i;
}
}
int lowbit(int x){
return x & -x;
}
void update(int x, int d){
while(x <= N){
t[x] += d;
x += lowbit(x);
}
}
int sum(int x){
int ans = 0;
while(x > 0){
ans += t[x];
ans %= MOD;
x -= lowbit(x);
}
return ans;
}
signed main(){
freopen("meaning.in", "r", stdin);
freopen("meaning.out", "w", stdout);
scanf("%lld", &T);
while(T--){
init();
scanf("%s", s);
scanf("%s", p);
lens = strlen(s);
lenp = strlen(p);
get();
kmp();
int ans = 1;
if(cnt == 0)
printf("%lld\n", ans);
else {
for(int i = 1; i <= cnt; i++)
flag[last[i]] = 1;
for(int i = 0; i < lens; i++){
pre[i] = pre[i - 1];
if(flag[i])
pre[i]++;
}
dp[1] = 1;
update(1, 1);
for(int i = 2; i <= cnt; i++){
int tmp = i - pre[last[i]] + pre[last[i] - lenp];
dp[i] = 1;
if(tmp > 0){
dp[i] += sum(tmp);
dp[i] %= MOD;
}
update(i, dp[i]);
}
for(int i = 1; i <= cnt; i++){
ans += dp[i];
ans %= MOD;
}
printf("%lld\n", ans);
}
}
return 0;
}
T4
题目描述
斐波那契序列是这样一个序列
输入格式
第一行一个数
第二行
输出格式
一个整数,表示最长斐波那契子序列长度。
输入样例
10
1 1 3 -1 2 0 5 -1 -1 8
输出样例
5
数据规模
对于
对于
题解
考虑像求最长不下降子序列一样,设
那么答案就是
考虑转移,如果能找到一个位置
朴素枚举为
完整代码
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
int read(){
int k = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')
f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
k = k * 10 + c - '0';
c = getchar();
}
return k * f;
}
void write(int x){
if(x < 0){
putchar('-');
x = -x;
}
if(x < 10)
putchar(x + '0');
else {
write(x / 10);
putchar(x % 10 + '0');
}
}
const int N = 3e3 + 9;
int a[N], dp[N][N], n, ans;
unordered_map <int, short> mp;
int main(){
freopen("fibonacci.in", "r", stdin);
freopen("fibonacci.out", "w", stdout);
n = read();
for(register int i = 1; i <= n; i++)
a[i] = read();
if(n == 1)
write(1);
else {
for(register int i = 1; i <= n; i++)
for(register int j = i + 1; j <= n; j++)
dp[i][j] = 1;
ans = 0;
for(register int i = n; i >= 1; i--){
for(register int j = 1; j < i; j++){
int k = mp[a[i] + a[j]];
if(k != 0)
dp[j][i] = max(dp[i][k] + 1, dp[j][i]);
}
mp[a[i]] = i;
}
for(register int i = 1; i <= n; i++)
for(register int j = 1; j < i; j++)
ans = max(ans, dp[j][i]);
}
if(ans == 0)
write(2);
else
write(ans + 1);
return 0;
}
本文来自博客园,作者:JPGOJCZX,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18422880
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效