牛客周赛 Round 142 题解
A 小苯的ovo3.0
知识点:语法
思路:分别判断三个字符是不是即可
Code
点击查看代码
void solve()
{
cin>>s;
if(s[0]=='o'||s[0]=='O')
{
if(s[2]=='o'||s[2]=='O')
{
if(s[1]=='v'||s[1]=='V')
{
cout<<"YES"<<endl;
return;
}
}
}
cout<<"NO"<<endl;
}
B 小苯的双端队列
知识点:语法
思路:设置两个指针,初始一个在最左边,一个在最右边,遍历序列,哪一个符合就往中间缩,一旦出现两个都不符合的情况说明序列不合法
Code
点击查看代码
void solve()
{
cin>>n;
vi a(n+1);
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
l=1,r=n;
for(int i=1;i<=n;i++)
{
if(a[i]==l)
{
l++;
continue;
}
if(a[i]==r)
{
r--;
continue;
}
cout<<"NO"<<endl;
return;
}
cout<<"YES"<<endl;
}
C 小苯的整除序列
知识点:贪心
思路:很容易注意到对于同一个数,在序列的前面整除它,比在序列的后面整除它更优,更容易让结果序列更长,所以我们贪心,从左侧遍历序列,一旦可以整除就接着试下一个数,能够整除的次数即为序列长度
Code
点击查看代码
void solve()
{
cin>>n;
vi a(n+1);
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int now=1;
for(int i=1;i<=n;i++)
{
if(a[i]%now==0)
{
now++;
}
}
cout<<now-1<<endl;
}
D 小苯的幼儿园
知识点:思维
思路:如果糖果数量总和不能整除小朋友的数量,一定不合法。因为每个小朋友只能操作一次,所以如果有一个小朋友糖的数量比平均值大 \(2\) 或以上,一定不合法,如果有一个小朋友糖的数量加上 \(1\) 依旧不是平均值,一定不合法,如果小朋友糖的数量比平均值大 \(1\),传给下一个小朋友,这样判断下来如果全符合,那么就可以达成均分
Code
点击查看代码
void solve()
{
cin>>n;
vi a(n+8);
int sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
if(sum%n!=0)
{
cout<<"NO"<<endl;
return;
}
int v=sum/n;
a[n+1]=a[1];
for(int i=1;i<=n+1;i++)
{
if(a[i]-v>=2||a[i]+1<v)
{
cout<<"NO"<<endl;
return;
}
if(a[i]==v+1)
{
a[i]-=1;
a[i+1]++;
}
}
cout<<"YES"<<endl;
}
E 小苯的区间操作
知识点:思维
思路:如果序列中有峰值,即 \(a_i>a_{i-1}\) 并且 \(a_i>a_{i+1}\),想要将峰值减成 \(0\),因为 \(a_{i-1}\) 和 \(a_{i+1}\) 的约束,所有想要包含 \(a_i\) 的操作区间一定也会包括 \(a_{i+1}\) 和 \(a_{i-1}\) ,如果想要将 \(a_i\) 作为端点,因为他是峰值,它旁边的数一定会先减成 \(0\),所以 \(a_i\) 永远不可能减成 \(0\),所以显然如果存在峰值,一定不合法,如果没有峰值呢?我们可以先找到一个最大值序列,将这个序列减成和外部数相同后合并成更大的序列,以此类推一定可以减成 \(0\),
点击查看代码
void solve()
{
cin>>n;
vi a(n+4);
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i = 1; i <= n;i++)
{
if(a[i]>a[i - 1]&&a[i]>a[i + 1])
{
cout<<"No"<<endl;
return;
}
}
cout<<"Yes"<<endl;
}
F 小苯的DFS
知识点:dfs,贪心
思路:由题意得,共有两个限制,对于某一棵子树来说,根节点权值必须必须是子树中的最小值,对于某一个父亲节点的两个儿子来说,先遍历子树中的最大值必须小于等于后遍历子树中的最小值。我们求出每个子树中的最大和最小权值,对每个子树儿子所构成的所有权值区间进行排序,凡是有不满足两个限制的,概率一律为 \(0\),对于满足限制的为合法情况,对于排好序的权值区间数组来讲,可能存在某些权值区间是一样的,意味着先遍历哪一个都可以,会产生多种情况,情况数量为相同权值区间数量阶乘的乘积(设相同权值区间的数量为 \(c_i\),设总遍历方案数为 \(k!\) ,结果为 \(\frac{c_{1}!\times c_{2}!\times \ldots}{k!}\))
Code
点击查看代码
int fac[M];
int inv[M];
void init()
{
fac[0] = 1;
for (int i = 1; i < M; i++)
{
fac[i] = fac[i - 1] * i % mod;
}
inv[M - 1] = ksm(fac[M - 1], mod - 2, mod);
for (int i = M - 2; i >= 0; i--)
{
inv[i] = inv[i + 1] * (i + 1) % mod;
}
}
vi adj[M];
int ok;
int ans;
vi mi, mx, a;
void dfs(int u, int fa)
{
mi[u] = a[u];
mx[u] = a[u];
vector<pii> p;
for (int v : adj[u])
{
if (v == fa)
continue;
dfs(v, u);
if (!ok)
return;
mi[u] = min(mi[u], mi[v]);
mx[u] = max(mx[u], mx[v]);
p.pb({mi[v], mx[v]});
}
if (a[u] != mi[u])
{
ok = 0;
return;
}
if (!p.empty())
{
sort(all(p));
for (int i = 0; i < (int)p.size() - 1; i++)
{
if (p[i].second > p[i + 1].first)
{
ok = 0;
return;
}
}
int res = 1;
int cnt = 1;
for (int i = 1; i < (int)p.size(); i++)
{
if (p[i] == p[i - 1])
{
cnt++;
}
else
{
res = res * fac[cnt] % mod;
cnt = 1;
}
}
res = res * fac[cnt] % mod;
int c = res * inv[p.size()] % mod;
ans = ans * c % mod;
}
}
void solve()
{
cin >> n;
a.resize(n + 1);
mx.resize(n + 1);
mi.resize(n + 1);
for (int i = 1; i <= n; i++)
{
adj[i].clear();
}
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
adj[u].pb(v);
adj[v].pb(u);
}
ok = 1;
ans = 1;
dfs(1, 0);
if (!ok)
{
cout << 0 << endl;
}
else
{
cout << ans << endl;
}
}

浙公网安备 33010602011771号