本期封面原图 制图redman
这场Div2难度绝对不对劲吧 D题5000人过?
A - Strong Password
题意
在字符串内加一个字符使得他的强度最高 强度的定义是每次出现和上一个字符不同的字符可以加一
思路
所以就在原本相同的里面插一个不同的字符 找不到就直接丢在最后面
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void solve()
{
string s;
cin>>s;
s=' '+s;
int n=s.size();
int flag=0;
for(int i=0;i<n;i++)
{
if(i>0)
printf("%c",s[i]);
if(s[i]==s[i+1] and flag==0)
{
flag=1;
char now=s[i];
now++;
if(now>'z')
now='a';
printf("%c",now);
}
}
if(flag==0)
{
char now=s[n-1];
now++;
if(now>'z')
now='a';
printf("%c",now);
}
printf("\n");
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
B - Make Three Regions
题意
在一个最多只有1个联通块的地图里能找到多少个格子使得将其变为阻碍方块刚好能形成3个联通块
思路
特别注意题目说了原本最多只有一个联通块 所以其实只需要找
X.X ...
... X.X
这两种情况就可以了 没有其他情况能让我的联通块刚好变成三个
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
int n;
string s[2];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
void solve()
{
scanf("%d",&n);
cin>>s[0]>>s[1];
int cnt=0;
for(int i=0;i<n;i++)
{
if(s[0][i]=='.' and s[1][i]=='.')
{
if(i>0 and i<n-1)
{
if(s[0][i-1]=='.' and s[0][i+1]=='.')
{
if(s[1][i-1]=='x' and s[1][i+1]=='x')
{
cnt++;
}
}
}
}
}
for(int i=0;i<n;i++)
{
if(s[0][i]=='.' and s[1][i]=='.')
{
if(i>0 and i<n-1)
{
if(s[1][i-1]=='.' and s[1][i+1]=='.')
{
if(s[0][i-1]=='x' and s[0][i+1]=='x')
{
cnt++;
}
}
}
}
}
printf("%d\n",cnt);
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
C - Even Positions
题意
定义一个括号序列的强度是每一对匹配上的括号之间距离的和 现在序列奇数位的字符全都不知道 要你最大化这个序列的长度
思路
因为是只有奇数位被抠掉 所以最后一个肯定是右括号 所以要优先把左括号安顿好 所有的左括号我们都先在他右边一格直接放一个右括号 然后右括号再往前找最近的空格位置
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void solve()
{
int n;
scanf("%d",&n);
string s;
cin>>s;
ll ans=0;
for(int i=0;i<n;i++)
{
if(s[i]=='(')
{
ans++;
s[i+1]=']';
}
}
// cout<<s<<endl;
for(int i=n-1;i>0;i--)
{
if(s[i]==')')
{
int j=i-1;
while(s[j]!='_')
j--;
ans+=i-j;
s[j]='[';
}
}
// cout<<s<<endl;
printf("%lld\n",ans);
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
D - Maximize the Root
题意
给一棵树 每次可以选择任意节点将他所有子孙的权值减一 他自己加一 操作任意次使得树的根节点的权值最大
思路
每次让根节点变大 下面的所有节点都要减一 所以影响最大值的就只有根节点子孙的最小权值节点 找到他 想办法让他变大 那么与上面同理 我们需要找到他的子孙中的最小权值节点 然后两个人平均一下
综上所述 我们要进行的是一个dfs递归的过程
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int N=200050;
int n;
int a[N];
int p[N];
vector<int> e[N];
int dfs(int now)
{
if(e[now].size()==0 and now!=1)
{
return a[now];
}
int m=1e9+7;
for(int i:e[now])
{
int tmp=dfs(i);
m=min(m,tmp);
}
if(now==1)
return m+a[1];
if(a[now]>m)
return m;
return (a[now]+m)/2;
}
void solve()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=2;i<=n;i++)
{
scanf("%d",&p[i]);
e[p[i]].push_back(i);
}
int ans=dfs(1);
printf("%d\n",ans);
for(int i=1;i<=n;i++)
{
e[i].clear();
}
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
E - Level Up
题意
k个经验升一级 等级严格大于怪物时怪物会逃跑 所以不会累计经验 每个怪物的等级告诉你 进行q次查询 每次问当k为给定值时能不能跟第i个怪物打起来 打起来输出YES
复盘
一开始想的是4秒感觉直接写简单优化下就能过 然后写的是这么个带记忆上下界的优化但是WA5了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll n,q;
const int N=200050;
ll a[N];
ll prel[N],prer[N];
bool check(ll i,ll x)
{
int cnt=0;
int lv=1;
for(int j=1;j<i;j++)
{
if(a[j]<lv)
continue;
cnt++;
if(cnt==x)
{
cnt=0;
lv++;
}
}
if(a[i]<lv)
return false;
return true;
}
void solve()
{
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
memset(prel,0,sizeof(prel));
memset(prer,n+1,sizeof(prer));
while(q--)
{
ll i,x;
scanf("%lld%lld",&i,&x);
if(prer[i]<=x)
{
printf("YES\n");
continue;
}
else if(prel[i]>=x)
{
printf("NO\n");
continue;
}
bool now=check(i,x);
if(now)
{
printf("YES\n");
prer[i]=x;
}
else
{
printf("NO\n");
prel[i]=x;
}
}
}
int main()
{
int T=1;
//scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
思路
那回过头来还是要老老实实预处理答案 对于每个怪兽都预处理一个最小的k保证这个k能够让我打这个怪兽 k的查找肯定是二分 但是现在已经是O(nlogn)了 如果我的check函数又是从头扫肯定不行 比刚才那个还慢 我们注意到其实需要的是前面的k的个数 所以我们可以用高级数据结构维护前面k的个数 可以用主席树 但是一看这个数据范围只有2e5 那干脆直接用树状数组维护一个桶就行了
代码
#include <bits/stdc++.h>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int N=200050;
int n;
int a[N],tr[N];
int p[N];
void add(int x,int y)
{
for(;x<=n;x+=lowbit(x))
{
tr[x]+=y;
}
}
int query(int x)
{
int res=0;
for(;x;x-=lowbit(x))
{
res+=tr[x];
}
return res;
}
bool check(int k,int i)
{
int sum=query(k);
int now=1+sum/k;
return now<=a[i];
}
void solve()
{
int q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
memset(tr,0,sizeof(tr));
for(int i=1;i<=n;i++)
{
int l=1,r=n;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid,i))
{
r=mid;
}
else
{
l=mid+1;
}
}
p[i]=l;
add(p[i],1);
}
while(q--)
{
int i,x;
scanf("%d%d",&i,&x);
if(p[i]<=x)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
}
int main()
{
int T=1;
//scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}