A-Strong Password(字符串 构造 贪心)
题意
给定一个由小写字母组成的字符串密码,定义一个密码的复杂度(输入时间):第一个字母需要两秒,其他字母如果与前一个字母相同,需要1秒,否则需要2秒,现在要求在字符串中插入任意一个小写字母使得输入时间最大(这里的better翻译错误,翻译为了最短时间),输出插入后的字符串
思路
直接从左往右遍历,直到找到两个连续相同的字母,在中间插入一个不同的字母即可,如果没有则加在字符串末尾,与字符串末尾的字母不同
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=1e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
void solve()
{
string s;
cin>>s;
int n=s.size();
bool flag=false;
if(n==1)
{
if(s[0]=='a')cout<<"ab"<<endl;
else cout<<s[0]<<(char)(s[0]-1)<<endl;//这里有个坑:char减去1会被转化为int类型,需要转化回来
return;
}
for(int i=0;i<s.size()-1;i++)
{
cout<<s[i];
if(s[i]==s[i+1]&&flag==false)
{
flag=true;
char tmp=s[i];
if(tmp=='a')tmp++;
else tmp--;
cout<<tmp;
flag=true;
}
}
cout<<s[s.size()-1];
if(!flag)
{
char tmp=s[s.size()-1];
if(tmp=='a')tmp++;
else tmp--;
cout<<tmp;
}
cout<<endl;
}
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
B-Make Three Regions(构造)
题意
给定一个2*n的矩阵,里面由两种方块组成:堵塞方块和自由方块,自由方块有且只会形成一个联通块(这个条件很重要),求符合条件的自由方块个数(把这个自由方块变成堵塞方块后恰好能把一个联通块割成3个联通块)
思路
因为自由方块有且只会形成一个联通块,所以只会有一种结构能够满足分割条件:
(黑色的是堵塞方块,白色的是自由方块,有点潦草,可以上下颠倒为另一种情况)
然后特判累加即可
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=2e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
char s[3][N];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>s[1][i];
for(int j=1;j<=n;j++)cin>>s[2][j];
if(n<3)
{
cout<<"0"<<endl;
return;
}
LL res=0;
for(int i=1;i+2<=n;i++)//两种特判
{
if(s[1][i]=='x'&&s[1][i+2]=='x'&&s[1][i+1]=='.')
{
if(s[2][i]==s[2][i+1]&&s[2][i+1]==s[2][i+2]&&s[2][i+2]=='.')
{
res++;
}
}
if(s[2][i]=='x'&&s[2][i+2]=='x'&&s[2][i+1]=='.')
{
if(s[1][i]==s[1][i+1]&&s[1][i+1]==s[1][i+2]&&s[1][i+2]=='.')
{
res++;
}
}
}
cout<<res<<endl;
}
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
C-Even Positions(数据结构-栈 构造 贪心)
题意
给定一个由'(',')'和'_'三种字符组成的字符串,'_'出现在所有的奇数位,现在需要我们在'_'中填入'('或')',使得每个括号一定能够配对(保证一定存在这样的字符串),使得字符串的分数最大(每个括号左右下标差的累加值)
思路
看到括号,就想到栈的使用,这道题的解法多样,我的解法使用了栈;
枚举原字符串,一共有三种字符,分别进行操作:
具体逻辑在代码中注释出来了
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<char,LL> PII;//开long long,求求你了,记得开long long
const LL N=2e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
char s[N];
void solve()
{
LL n;
cin>>n;
stack<PII> q;
for(int i=1;i<=n;i++)cin>>s[i];
LL res=0;
for(int i=1;i<=n;i++)
{
if(s[i]=='_')//碰到'_'
{
if(q.size()&&(q.top().first=='('))//如果栈顶为左括号,优先满足
{
res+=(i-q.top().second);//配对成功
q.pop();
}
else//否则入栈等待右括号
{
q.push({'_',i});
}
}
else if(s[i]=='(')//碰到'('
{
q.push({'(',i});//直接入栈,等右边的‘_’
}
else if(s[i]==')')//碰到')'
{
//if(q.size())cout<<q.top().first<<endl;
if(q.size()&&(q.top().first=='('||q.top().first=='_'))'('和‘_’都可以配对
{
res+=(i-q.top().second);//配对成功
q.pop();
}
}
}
//cout<<q.size()<<endl;//这里看到栈到后面总是空的,不用再处理了
cout<<res<<endl;
}
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
D-Maximize the Root(带权树 dfs min)
题意
给定一个以1为根节点,共有n个带权顶点的树,可以对至少有一个子节点的顶点进行操作,将这个顶点的后代节点(包括子顶点、孙顶点等)的权值-1,该顶点权值+1(但是要保证每个顶点的权值都不为负数),求经过若干这种操作后,顶点1的权值的最大值。
思路
这道题赛时没有A出来,当时想到了dfs求子树最小值这种做法,但是因为能够加1的不只是根节点,所以单纯取最小值是不行的,非1顶点也可以通过压榨权值比它大的子节点+1,所以需要考虑子树中子节点最低权值比父节点权值大的情况,赛后看到大佬的平均写法,真的太妙了(我还是太蒻了)
代码
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;//开long long,求求你了,记得开long long
const LL N=2e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了
int p[N];
int h[N];
int e[N];
int ne[N];
int idx=0;
void add(int a,int b)//邻接表存图
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
int dfs(int u)
{
int hh=p[u];//当前节点的初始权值
LL t=1e17;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
int tmp=dfs(j);//遍历每一个子节点,找到最小权值
t=min((LL)tmp,t);
}
if(u==1)//到根节点,直接加上当前最新的子节点的最小值
{
if(t!=1e17)
{
hh+=t;
}
cout<<hh<<endl;
return 0;
}
if(t!=1e17&&t>=hh)//子节点比父节点权值大,说明可以通过若干操作进行平均,增大父节点的权值
{
hh=(hh+t)/2;//取平均
}
if(hh>t)
{
hh=t;//如果子节点权值比父节点还小,就不能操作,而且会降低这棵树的最低权值
}
return hh;
}
void solve()
{
memset(h,-1,sizeof h);
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>p[i];//初始权值
for(int i=2;i<=n;i++)
{
int x;
cin>>x;
add(x,i);
}
dfs(1);
}
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
E-Level Up
F-Chips on a Line
窝滴水平不足,剩下的两题补不了,先放个传送门,以后再补。