2019.10.30 csp-s模拟测试94 反思总结

头一次做图巨的模拟题OWO

自从上一次听图巨讲课然后骗了小礼物以后一直对图巨印象挺好的233

 

 

T1:

对于XY取对数=Y*log(x)

对于Y!取对数=log(1*2*3*...*Y)=log1+log2+log3+...+logY

因为数字大小不超过1e5,直接累加最后比较就可以了

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int t,x,y;
double a,b;
int main()
{
    freopen("yuuutsu.in","r",stdin);
    freopen("yuuutsu.out","w",stdout);
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&x,&y);
        a=y*log(x);
        b=0;
        for(int i=1;i<=y;i++){
            b+=log(i);
        }
        if(a<=b)printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
View Code

 

T2:

每一次操作会让区间整体加或减->在差分数组上首位加减

列出目标序列的差分数组,可以进行操作让一个位置的数字移动k步,如果有大小相同的数字撞在一起就会消掉,不同的话可以合并。想起星空这道题,不同的是今天的T2只能走k一种步数且差分值并不只代表一种状态

目标是要让所有的值变成0,又想到一道跳斑马线的题……?考虑把位置对于k取模余数不同的数字分开处理。维护位置对于k取模后余数为下标,记录差分值之和的m数组。用树状数组维护当前的m是否都为0。

#include<iostream>
#include<cstdio>
using namespace std;
const int N=2e6+10;
int n,k,q,a[N],sum[N],m[N];
long long tree[N];
void add(int x,int y){
    for(;x<=k;x+=(x&-x))tree[x]+=y;
}
long long ask(int x){
    long long num=0;
    for(;x;x-=(x&-x))num+=tree[x];
    return num;
}
int main()
{
    freopen("august.in","r",stdin);
    freopen("august.out","w",stdout);
    scanf("%d%d%d",&n,&k,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        m[i%k]+=a[i]-a[i-1];
    }
    m[(n+1)%k]+=-a[n];
    for(int i=0;i<k;i++){
        add(i+1,(m[i]!=0));
    }
    if(!ask(k))printf("Yes\n");
    else printf("No\n");
    for(int i=1,x,pos;i<=q;i++){
        scanf("%d%d",&pos,&x);
        int pos0=pos%k,pos1=(pos+1)%k;
        int val=(m[pos0]!=0),val1=(m[pos1]!=0);
        m[pos0]=m[pos0]-a[pos]+a[pos-1];
        m[pos1]=m[pos1]-a[pos+1]+a[pos];
        a[pos]+=x;
        m[pos0]=m[pos0]+a[pos]-a[pos-1];
        m[pos1]=m[pos1]+a[pos+1]-a[pos];
        add(pos0+1,(m[pos0]!=0)-val);
        add(pos1+1,(m[pos1]!=0)-val1);
        if(!ask(k))printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
View Code

 发现自己对于m是否都为0的处理过于麻烦了…这是何种山路十八弯的脑回路才会想到这种处理…

其实是中途思路锅了,保留了树状数组的写法XD其实直接记一个m不为0的数量,每次m变化的时候进行更新就好了

 

T3:

将问题转化成,对于树上的一个点,会对多少区间产生贡献。

线段树维护子树中存在哪些位置的点,线段树下标是在a数组中的位置。如果这个点可以对一段区间产生贡献,那么这段区间在线段树种一定是连续的1,中间若存在0则代表这段区间中在更高的地方存在点。在线段树上统计答案,记录线段树每个节点从左端点开始最长的一段1的长度lonl,从右端点开始最长的一段1的长度lonr,以及包含的区间个数val。val=左儿子的val+右儿子的val+左儿子lonr*右儿子lonl(端点在两边的区间数量)。这样计算一定不重不漏,有线段树分治的意味。

维护节点x的线段树的时候,对所有儿子进行线段树合并,再把x点insert进去。注意当前节点线段树root的区间个数要减去节点儿子们的区间个数,才能用来累计答案。

#include<iostream>
#include<cstdio>
using namespace std;
const int N=2000010;
int n,tot,cnt;
int ver[N],Next[N],head[N];
int a[N],b[N],pos[N],T[N],L[N*22],R[N*22],lonl[N*22],lonr[N*22];
long long ans,sum[N],val[N*22];
void add(int x,int y){
    ver[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}
void update(int p,int l,int r){
    int mid=(l+r)/2;
    if(lonl[L[p]]==mid-l+1)lonl[p]=mid-l+1+lonl[R[p]];
    else lonl[p]=lonl[L[p]];
    if(lonr[R[p]]==r-mid)lonr[p]=r-mid+lonr[L[p]];
    else lonr[p]=lonr[R[p]];
    val[p]=val[L[p]]+val[R[p]]+1ll*lonr[L[p]]*lonl[R[p]];
}
void change(int &p,int p0,int l,int r){
    if(!p){
        p=p0;
        return;
    }
    int mid=(l+r)/2;
    if(L[p0])change(L[p],L[p0],l,mid);
    if(R[p0])change(R[p],R[p0],mid+1,r);
    update(p,l,r);
}
void ins(int &p,int l,int r,int pos){
    if(!p)p=++cnt;
    if(l==r){
        lonl[p]=lonr[p]=1;
        val[p]=0;
        return;
    }
    int mid=(l+r)/2;
    if(pos<=mid)ins(L[p],l,mid,pos);
    else ins(R[p],mid+1,r,pos);
    update(p,l,r);
}
void dfs(int x){
    for(int i=head[x];i;i=Next[i]){
        int y=ver[i];
        dfs(y);
        sum[x]+=sum[y];
        change(T[x],T[y],1,n);
    }
    ins(T[x],1,n,pos[x]);
    long long num=val[T[x]];
    ans+=(num-sum[x])*b[x];
    sum[x]=num;
}
int main()
{
    freopen("sagittarius.in","r",stdin);
    freopen("sagittarius.out","w",stdout);
    scanf("%d",&n);
    for(int i=2,x;i<=n;i++){
        scanf("%d",&x);
        add(x,i);
//        st[i][0]=x;
    }
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),pos[a[i]]=i;
    for(int i=1;i<=n;i++)scanf("%d",&b[i]),ans+=b[i];
    dfs(1);
    printf("%lld\n",ans);
    return 0;
    
}
View Code

 

posted @ 2019-10-30 21:36  Chloris_Black  阅读(215)  评论(0编辑  收藏  举报