Educational Codeforces Round 162 (Rated for Div. 2)
不会 F 的场。
A
答案是最左的 \(1\) 和最右的 \(1\) 之间的 \(0\) 的个数。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
int n;
cin>>n;
int mn=-1,mx=-1,cnt=0;
for (int i=0; i<n; i++){
int x;
cin>>x;
if (x==1){
if (mn==-1){
mn=i;
}
mx=i;
cnt++;
}
}
cout<<mx-mn+1-cnt<<"\n";
}
return 0;
}
B
每次优先打最近的怪物。证明不难。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 3e5+5;
ll n,k;
struct node {
ll dis,h;
bool operator < (const node &x) const {
return dis<x.dis;
}
} a[N];
void solve(){
cin>>n>>k;
for (int i=1; i<=n; i++){
cin>>a[i].h;
}
for (int i=1; i<=n; i++){
cin>>a[i].dis;
a[i].dis=abs(a[i].dis);
}
sort(a+1,a+1+n);
ll sum=0;
for (int i=1; i<=n; i++){
ll mnt=(sum+a[i].h+k-1)/k;
if (a[i].dis<mnt){
cout<<"NO\n";
return;
}
sum+=a[i].h;
}
cout<<"YES\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
C
发现 \(1\) 只能加,不能减,至少要加 \(1\)。因此,只要 \([l,r]\) 中能减去的(即 \(\sum_{i=l}^r {a_i}-(r-l+1)\))大于等于 \(1\) 的个数就可以了。直接前缀和。
场上又写复杂了。失败。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 3e5+5;
ll bit[N];
void M(int p,ll x){
while (p<N){
bit[p]+=x,p+=p&-p;
}
}
ll Q(int p){
ll res=0;
while (p){
res+=bit[p],p-=p&-p;
}
return res;
}
int n,q;
ll c[N],sum[N];
void solve(){
cin>>n>>q;
for (int i=1; i<=n; i++){
cin>>c[i];
sum[i]=sum[i-1]+c[i]-1;
}
for (int i=1; i<=n; i++){
bit[i]=0;
}
for (int i=1; i<=n; i++){
if (c[i]==1){
M(i,1);
}
}
while (q--){
int l,r;
cin>>l>>r;
if (l==r){
cout<<"NO\n";
continue;
}
ll cg=sum[r]-sum[l-1];
ll nd=Q(r)-Q(l-1);
if (cg>=nd){
cout<<"YES\n";
}
else{
cout<<"NO\n";
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
D
左右二分。必须:
-
能开始吃,即不能全相同。这个可以表达为 \(\min\neq \max\)。
-
和大于这个 \(a_i\)。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 3e5+5;
ll n,a[N],lg[N],mx[N][22],mn[N][22],sum[N];
void init(){
lg[1]=0;
for (int i=2; i<N; i++){
lg[i]=lg[i/2]+1;
}
}
ll qmx(ll x,ll y){
int s=lg[y-x+1];
return max(mx[x][s],mx[y-(1<<s)+1][s]);
}
ll qmn(ll x,ll y){
int s=lg[y-x+1];
return min(mn[x][s],mn[y-(1<<s)+1][s]);
}
void cal(){
for (int i=1; i<=n; i++){
mn[i][0]=mx[i][0]=a[i];
}
for (int j=1; j<=21; j++){
for (int i=1; i+(1<<j)-1<=n; i++){
mx[i][j]=max(mx[i][j-1],mx[i+(1<<j-1)][j-1]);
mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]);
}
}
}
ll gts(int l,int r){
return sum[r]-sum[l-1];
}
ll gtl(int i){
if (a[i-1]>a[i]){
return 1;
}
int l=0,r=i;
while (l+1<r){
int mid=l+r>>1;
if (qmn(mid,i-1)==qmx(mid,i-1)){
r=mid;
}
else{
l=mid;
}
}
int lb=0,rb=l+1;
while (lb+1<rb){
int mid=lb+rb>>1;
if (gts(mid,i-1)<=a[i]){
rb=mid;
}
else{
lb=mid;
}
}
if (lb==0){
return 1e9;
}
return i-lb;
}
ll gtr(int i){
if (a[i+1]>a[i]){
return 1;
}
int l=i,r=n+1;
while (l+1<r){
int mid=l+r>>1;
if (qmn(i+1,mid)==qmx(i+1,mid)){
l=mid;
}
else{
r=mid;
}
}
int lb=r-1,rb=n+1;
while (lb+1<rb){
int mid=lb+rb>>1;
if (gts(i+1,mid)<=a[i]){
lb=mid;
}
else{
rb=mid;
}
}
if (rb==n+1){
return 1e9;
}
return rb-i;
}
void solve(){
cin>>n;
for (int i=1; i<=n; i++){
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
a[n+1]=0;
cal();
for (int i=1; i<=n; i++){
ll res=min(gtl(i),gtr(i));
if (res==1e9){
cout<<-1<<" ";
}
else{
cout<<res<<" ";
}
}
cout<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
init();
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
E
建一个虚树 dp。维护 \(dp_i\) 为当前这个节点的往上还没有遇到其他同颜色节点的点的个数。就很好做了。
听说可以启发式合并,但是我不会。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ll = long long;
const int N = 2e5+5;
int n,a[N],cnt,dfn[N],d[N],f[N][20];
vector<int> c[N],g[N];
void dfs(int u,int fa){
dfn[u]=++cnt;
f[u][0]=fa;
for (int i=1; i<20; i++){
f[u][i]=f[f[u][i-1]][i-1];
}
for (auto v : g[u]){
if (v^fa){
d[v]=d[u]+1,dfs(v,u);
}
}
}
bool cmp(int x,int y){
return dfn[x]<dfn[y];
}
int lca(int u,int v){
if (d[u]>d[v]){
swap(u,v);
}
int dif=d[v]-d[u];
for (int i=0; i<20; i++){
if (dif>>i&1){
v=f[v][i];
}
}
if (u==v){
return u;
}
for (int i=19; i>=0; i--){
if (f[u][i]!=f[v][i]){
u=f[u][i],v=f[v][i];
}
}
return f[u][0];
}
int st[N],top,is[N];
void bd(int i){
g[1].clear();
top=1;
st[top]=1;
for (auto u : c[i]){
is[u]=1;
if (u!=1){
int lc=lca(u,st[top]);
if (lc!=st[top]){
while (dfn[st[top-1]]>dfn[lc]){
g[st[top-1]].push_back(st[top]);
top--;
}
if (dfn[lc]>dfn[st[top-1]]){
g[lc].clear();
g[lc].push_back(st[top]);
st[top]=lc;
}
else{
g[lc].push_back(st[top--]);
}
}
g[u].clear();
st[++top]=u;
}
}
for (int j=1; j<top; j++){
g[st[j]].push_back(st[j+1]);
}
}
ll ans,dp[N];
void dfs2(int u){
if (g[u].size()==0){
dp[u]=is[u]?1:0;
return;
}
ll sum=0;
for (auto v : g[u]){
dfs2(v);
sum+=dp[v];
}
if (is[u]){
ans+=sum;
dp[u]=1;
}
else{
ll ad=0;
for (auto v : g[u]){
ad+=1ll*dp[v]*(sum-dp[v]);
}
ad=ad/2;
ans+=ad;
dp[u]=sum;
}
}
void solve(){
cin>>n;
cnt=0;
for (int i=1; i<=n; i++){
g[i].clear();
c[i].clear();
}
for (int i=1; i<=n; i++){
int x;
cin>>x;
c[x].push_back(i);
}
for (int i=1; i<n; i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
ans=0;
for (int i=1; i<=n; i++){
sort(c[i].begin(),c[i].end(),cmp);
bd(i);
dfs2(1);
for (auto u : c[i]){
is[u]=0;
}
}
cout<<ans<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}