[CSP-S模拟测试94]题解
A.凉宫春日的忧郁
高精硬上似乎跑不过,其实可以都取个$log$。那么只需要比较$y\times log ^x$和$\sum \limits _{i=1}^y log^i$就好了。
#include<bits/stdc++.h> using namespace std; int T; double x,y; void work() { scanf("%lf%lf",&x,&y); double res1=y*log2(x); double res2=0; for(int i=1;i<=y;i++) res2+=log2(double(i)); if(res1<=res2)puts("Yes"); else puts("No"); } int main() { freopen("yuuutsu.in","r",stdin); freopen("yuuutsu.out","w",stdout); scanf("%d",&T); while(T--)work(); return 0; }
B.漫无止境的八月
显然目标区间合法的充要条件是:把位置按照$mod \ K$意义分组,每组的权值和应该相等。
必要性:每次操作对于每一组的改变量都相同,所以最终的和也必然相等。
充分性:……很显然吧。
直接Hash表维护就好了,每次修改完判断是不是只有一种权值和即可。
#include<cstdio> #include<iostream> #include<cstring> #define ol using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } const int N=2e6+5; int n,K,Q,a[N],sum[N]; struct Hashtable { #define mod 19260817 int tot,head[19260820],nxt[N],to[N],val[N]; int &operator [] (int v) { int x=v%mod; for(int i=head[x];i;i=nxt[i]) if(to[i]==v)return val[i]; to[++tot]=v;nxt[tot]=head[x]; head[x]=tot; return val[tot]=0; } }s; int main() { #ifdef ol freopen("august.in","r",stdin); freopen("august.out","w",stdout); #endif n=read();K=read();Q=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) sum[i%K]+=a[i]; for(int i=0;i<K;i++) s[sum[i]]++; if(s[sum[0]]==K)puts("Yes"); else puts("No"); while(Q--) { int x=read(),val=read(); a[x]+=val; s[sum[x%K]]--; sum[x%K]+=val; s[sum[x%K]]++; if(s[sum[0]]==K)puts("Yes"); else puts("No"); } return 0; }
C.射手座之日
构造一个新的点权$v'[x]=v[x]-v[fa[x]]$,那么区间权值就成了区间内所有元素的$lca$的权值和,从每个点的角度考虑就是它作为一些连续点的祖先的方案数再乘上点权。
对于每个点建一棵线段树,维护左侧起最长连续段的端点,右侧起最长连续段的端点和方案数,线段树合并即可,维护过程类似于《山海经》。
方案数就是可以取的连续区间数,即$\frac {(r-l+1)(r-l+2)}{2}$,除以2可以留在外面做。
#include<cstdio> #include<iostream> #include<cstring> #define ol using namespace std; typedef long long ll; int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } const int N=2e5+5; int n,fa[N],a[N],pos[N]; int to[N<<1],head[N],nxt[N<<1],tot; ll v[N],ans; void add(int x,int y) { to[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } int root[N],type,lp[N*30],rp[N*30],ls[N*30],rs[N*30]; ll w[N*30]; void up(int k,int l,int r) { int mid=l+r>>1; lp[k]=lp[ls[k]];rp[k]=rp[rs[k]]; w[k]=w[ls[k]]+w[rs[k]]; if(rp[ls[k]]&&lp[rs[k]]) { w[k]-=1LL*(mid-rp[ls[k]]+1)*(mid-rp[ls[k]]+2)+1LL*(lp[rs[k]]-mid)*(lp[rs[k]]-mid+1); w[k]+=1LL*(lp[rs[k]]-rp[ls[k]]+1)*(lp[rs[k]]-rp[ls[k]]+2); } if(lp[ls[k]]==mid)lp[k]=lp[rs[k]]?lp[rs[k]]:mid; if(rp[rs[k]]==mid+1)rp[k]=rp[ls[k]]?rp[ls[k]]:mid+1; } void update(int &k,int l,int r,int pos) { if(!k)k=++type; if(l==r) { lp[k]=rp[k]=l;w[k]=2; return ; } int mid=l+r>>1; if(pos<=mid)update(ls[k],l,mid,pos); else update(rs[k],mid+1,r,pos); up(k,l,r); } int merge(int x,int y,int l,int r) { if(!x||!y)return x+y; if(l==r)return x; int mid=l+r>>1; ls[x]=merge(ls[x],ls[y],l,mid); rs[x]=merge(rs[x],rs[y],mid+1,r); up(x,l,r); return x; } void dfs(int x) { update(root[x],1,n,pos[x]); for(int i=head[x];i;i=nxt[i]) { int y=to[i]; dfs(y); merge(root[x],root[y],1,n); } ans+=w[root[x]]/2*v[x]; } int main() { #ifdef ol freopen("sagittarius.in","r",stdin); freopen("sagittarius.out","w",stdout); #endif n=read(); for(int i=2;i<=n;i++) { fa[i]=read(); add(fa[i],i); } for(int i=1;i<=n;i++) a[i]=read(),pos[a[i]]=i; for(int i=1;i<=n;i++) v[i]=read(); for(int i=n;i;i--) v[i]-=v[fa[i]]; dfs(1); printf("%lld\n",ans); return 0; }
兴许青竹早凋,碧梧已僵,人事本难防。