2024.9.11
今日总结
1:楼房
这个题目主要用了离散化和线段树来解决。
首先考虑暴力的思想:首先用一个数组来存储每个点的高度,对所有的高度去一个Max
但是这么做肯定会超时。那么我们可以用一个线段树来维护每一个高度的Max使其做到查找的时间为O(1),只考虑可能存在拐点的位置,对每个拐点离散后对每个位置更新最大高度,最后扫描一遍离散序列,统计拐点数量并记录存在的位置,即可求出答案总体时间复杂度O(nlogn)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int M = N << 1;
int n,cnt;
int c[M],f[M],p[M];
//c数组记录离散后的高度
vector<pair<int,int>> v;//记录拐点的坐标
struct Node
{
int l,r;
int h;
}s[N];
bool cmp(const Node &x,const Node &y)
{
return x.h > y.h;
}
int query(const int &x)//查询最大值操作
{
if(x == f[x]) return x;
return f[x] = query(f[x]);
}
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
{
cin >> s[i].h >> s[i].l >> s[i].r;
p[i] = s[i].l,p[i + n] = s[i].r;
}
sort(s + 1,s + n + 1,cmp);
sort(p + 1,p + n * 2 + 1);//离散化
cnt = unique(p + 1,p + n * 2 + 1) - p - 1;
for(int i = 1;i <= cnt;i ++)
f[i] = i;//并查集初始化
for(int i = 1;i <= n;i ++)
{
s[i].l = lower_bound(p + 1,p + cnt + 1,s[i].l) - p;
s[i].r = lower_bound(p + 1,p + cnt + 1,s[i].r) - p;
for(int j = query(s[i].r - 1);j >= s[i].l;j = query(j - 1))
c[j] = s[i].h,f[j] = f[j - 1];//更新答案
}
for(int i = 1;i <= cnt;i ++)
{
if(c[i] != c[i - 1])
{
v.push_back({p[i],c[i - 1]});
v.push_back({p[i],c[i]});//找到节点
}
}
printf("%d\n",v.size());
for(auto &i : v)
cout << i.first << ' ' << i.second << endl;//输出x,y;
return 0;
}
2:单词游戏
这个题目是一个树形dp的题目。中间使用Floyed,判断那两个单词可以进行匹配,以防漏算掉最优解
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int M = 20;
int n,ans;
int len[M],c[M][M];
char s[M][5 * M];
struct Node
{
int num,pos;//num表示最大长度
}f[N * 4];
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
{
scanf("%s",s[i]);
len[i] = strlen(s[i]);
f[1 << (i - 1)].num = len[i];
f[1 << (i - 1)].pos = i;
ans = max(ans,len[i]);//运用贪心的思想先记录下最长的单词长度
}
for(int i = 1;i <= n;i ++)//两层循环遍历每一个单词
for(int j = 1;j <= n;j ++)
{
if(s[i][len[i] - 1] == s[j][0])//预处理树形dp
c[i][j] =1;
}
for(int i = 1;i < (1 << n);i ++)//运用FLoyed判断两个单词是否可以进行匹配
if(f[i].num)
for(int j = 1;j <= n;j ++)
if(c[f[i].pos][j])
if(!(i & 1 << (j - 1)))//是否可以进行匹配
if(len[j] + f[i].num > f[i | (1 << (j - 1))].num)//更新num
{
f[i | (1 << (j - 1))].num = len[j] + f[i].num;//动态转移方程(通过父节点和子节点的转移)
f[i | (1 << (j - 1))].pos = j;
ans = max(ans,f[i | (1 << (j - 1))].num);
}
printf("%d\n",ans);
return 0;
}