10.6 考试

T1

三个操作实际上是两个

1.把x -1

2.把x *k

而100000的ans也不过是50步,因为是指数增长

设 f[i] 为走到i这个值用到的最少步数

那可以枚举步数,然后来更新它能走到的位置

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=1000006;

int n;
int f[N*10];

int main(){
    
    scanf("%d",&n);
    mem(f,-1);
    f[1]=0;
    int step=0;
    while(f[n]==-1)
    {
        ++step;
        for(int i=0;i<=n+50;++i)
            if(f[i]!=-1)
            {
                if(f[i*(step-f[i])]==-1)
                    f[i*(step-f[i])]=step;
                if(i>0)
                {
                    if(f[i-1]==-1)
                        f[i-1]=f[i]+1;
                    else
                        if(f[i-1]>f[i]+1)
                            f[i-1]=f[i]+1;
                }
            }
    }
    cout<<f[n];
}
T1

 

T2

不知道正解是什么

他们从网上找了一篇17page的英文论文,我表示看不懂

然后 正哥打了杜教筛,O(n^(1/3)),正解好象是O(n^(0.4))...

ans=

x/(i*i)可以分块,然后就转化成了求mu的前缀和

要求前缀和范围是1e9,但是只能预处理7e7...

所以要用杜教筛...(好,联赛水题)

............(1)

 

这个就是莫比乌斯反演那个东西

只有当i==1的时候,才会==1

..........(2)

这个证明的话

(1)式,i=d*T,d是因数,T是倍数

(2)式,就变成 枚举倍数,实际上是一样的

然后(2)式 是递归形式,可以递归求,而且(2)式也可以分块求

然后就可以在O(n^(1/3))计算出来了

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define ll long long
#define dd double
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=70000006;
const int mod=76543;

int prime[2433706],cnt;
bool he[N];
int mu[N];

void chu()
{
    mu[1]=1;
    for(int i=2;i<N;++i)
    {
        if(!he[i])
        {
            prime[++cnt]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=cnt&&(ll)prime[j]*i<N;++j)
        {
            he[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }

    for(int i=1;i<N;++i)
        mu[i]+=mu[i-1];
}

ll n;

struct son
{
    ll u,v;
    int next;
}a1[N/10];
int first[mod],e,ttt;
inline void addbian(ll u,ll v)
{
    ttt=u%mod;
    a1[e].v=v;
    a1[e].u=u;
    a1[e].next=first[ttt];
    first[ttt]=e++;
}

ll presum(ll x)
{
    if(x<N)
        return mu[x];
    int kkk=x%mod;
    for(int i=first[kkk];i!=-1;i=a1[i].next)
        if(a1[i].u==x)
            return a1[i].v;
    ll nx,ans=1;
    for(ll i=2;i<=x;)
    {
        nx=x/(x/i);
        ans-=(nx-i+1)*presum(x/i);
        i=nx+1;
    }
    addbian(x,ans);
    return ans;
}

ll get(ll s,ll t)
{
    return presum(t)-presum(s-1);
}

int main(){

    mem(first,-1);

    chu();
    
    scanf("%lld",&n);
    ll q1=sqrt((dd)n),nx,ans=0;
    for(ll i=1;i<=q1;)
    {
        nx=sqrt( n/(n/(i*i)) );
        ans+=(n/(i*i))*get(i,nx);
        i=nx+1;
    }
    cout<<ans;
}
T2

 

T3

模拟Treap可以60分

正解是 线段树
首先把询问全都离线下来,离散一下

按照k为下标W为权值建线段树

由于是大根堆,ku和kv的lca其实就是[ku,kv]区间w最大的那个值(这个其实可以想想Treap的建树过程)

然后问题就只剩下 求ku,kv,lca到根节点的距离d了

d=pos向左向右的最长上升序列 (pos节点的父亲节点的w一定比它大)

这个 最长上升序列长度 就可以用线段树维护,这跟bzoj2957楼房重建一样了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int N=200006;

struct Q
{
    int op;
    ll t[2];
}q[N];

struct LI
{
    int pos,ff;
    ll val;
    bool friend operator < (LI a,LI b)
    {
        return a.val<b.val;
    }
}li[N*2];
int con;

ll val[N*4];
int dui[N*4];

struct TREE
{
    ll mx[N*8];
    int cnt[N*8];
    int cal(ll c,int l,int r,int x)
    {
        if(l==r)
            return mx[x]>c;
        int mid=(l+r)>>1;
        if(mx[x<<1]<=c)
            return cal(c,mid+1,r,x<<1|1);
        return cal(c,l,mid,x<<1)+cnt[x]-cnt[x<<1];
    }
    inline void pushup(int l,int r,int x)
    {
        int mid=(l+r)>>1;
        mx[x]=(mx[x<<1]>mx[x<<1|1]?mx[x<<1]:mx[x<<1|1]);
        cnt[x]=cnt[x<<1]+cal(mx[x<<1],mid+1,r,x<<1|1);
    }
    void add(int pos,ll c,int l,int r,int x)
    {
        if(l==r)
        {
            mx[x]=c;cnt[x]=1;
            return ;
        }
        int mid=(l+r)>>1;
        if(pos<=mid)
            add(pos,c,l,mid,x<<1);
        else
            add(pos,c,mid+1,r,x<<1|1);
        pushup(l,r,x);
    }
    ll qqmax(int L,int R,int l,int r,int x)
    {
        if(L<=l&&r<=R)
            return mx[x];
        int mid=(l+r)>>1;
        ll ans=0;
        if(L<=mid)
            ans=max(ans,qqmax(L,R,l,mid,x<<1));
        if(mid<R)
            ans=max(ans,qqmax(L,R,mid+1,r,x<<1|1));
        return ans;
    }
    int qq(int L,int R,int l,int r,int x)
    {
        //printf("Tsh  L=%d R=%d l=%d r=%d x=%d\n",L,R,l,r,x);
        if(L<=l&&r<=R)
            return cnt[x];
        int mid=(l+r)>>1,ans=0;
        if(R<=mid)
            return qq(L,R,l,mid,x<<1);
        if(mid<L)
            return qq(L,R,mid+1,r,x<<1|1);
        return qq(L,mid,l,mid,x<<1)+cal(qqmax(L,R,l,mid,x<<1),mid+1,r,x<<1|1);
    }
}Tsh;

struct TREe
{
    ll mx[N*8];
    int cnt[N*8];
    int cal(ll c,int l,int r,int x)
    {
        if(l==r)
            return mx[x]>c;
        int mid=(l+r)>>1;
        if(mx[x<<1|1]<=c)
            return cal(c,l,mid,x<<1);
        return cal(c,mid+1,r,x<<1|1)+cnt[x]-cnt[x<<1|1];
    }
    inline void pushup(int l,int r,int x)
    {
        int mid=(l+r)>>1;
        mx[x]=(mx[x<<1]>mx[x<<1|1]?mx[x<<1]:mx[x<<1|1]);
        cnt[x]=cnt[x<<1|1]+cal(mx[x<<1|1],l,mid,x<<1);
    }
    void add(int pos,ll c,int l,int r,int x)
    {
        if(l==r)
        {
            mx[x]=c;cnt[x]=1;
            return ;
        }
        int mid=(l+r)>>1;
        if(pos<=mid)
            add(pos,c,l,mid,x<<1);
        else
            add(pos,c,mid+1,r,x<<1|1);
        pushup(l,r,x);
    }
    ll qqmax(int L,int R,int l,int r,int x)
    {
        if(L<=l&&r<=R)
            return mx[x];
        int mid=(l+r)>>1;
        ll ans=0;
        if(L<=mid)
            ans=max(ans,qqmax(L,R,l,mid,x<<1));
        if(mid<R)
            ans=max(ans,qqmax(L,R,mid+1,r,x<<1|1));
        return ans;
    }
    int qq(int L,int R,int l,int r,int x)
    {
        //printf("Txi  L=%d R=%d l=%d r=%d x=%d\n",L,R,l,r,x);
        if(L<=l&&r<=R)
            return cnt[x];
        int mid=(l+r)>>1,ans=0;
        if(R<=mid)
            return qq(L,R,l,mid,x<<1);
        if(mid<L)
            return qq(L,R,mid+1,r,x<<1|1);
        return qq(L,R,mid+1,r,x<<1|1)+cal(qqmax(L,R,mid+1,r,x<<1|1),l,mid,x<<1);
    }
}Txi;

int n,mm;

int get(int pos)
{
    //printf("pos=%d\n",pos);
    return Tsh.qq(pos,mm,1,mm,1)+Txi.qq(1,pos,1,mm,1);
}

void lisan()
{
    for(int i=1;i<=n;++i)
    {
        if(q[i].op==0)
            li[++con]=(LI){i,0,q[i].t[0]};
        else
            if(q[i].op==1)
                li[++con]=(LI){i,0,q[i].t[0]};
        else
        {
            li[++con]=(LI){i,0,q[i].t[0]};
            li[++con]=(LI){i,1,q[i].t[1]};
        }
    }
    sort(li+1,li+1+con);
    li[0].val=-111;mm=0;
    for(int i=1;i<=con;++i)
    {
        if( li[i].val==li[i-1].val )
            q[li[i].pos].t[li[i].ff]=mm;
        else
            q[li[i].pos].t[li[i].ff]=++mm;
    }

    con=0;
    for(int i=1;i<=n;++i)
        if(q[i].op==0)
            li[++con]=(LI){i,1,q[i].t[1]};
    sort(li+1,li+1+con);
    for(int i=1;i<=con;++i)
    {
        q[li[i].pos].t[li[i].ff]=i;
        dui[i]=q[li[i].pos].t[0];
    }
}

int main(){

    //freopen("T3.in","r",stdin);

    scanf("%d",&n);

    for(int i=1;i<=n;++i)
    {
        scanf("%d",&q[i].op);
        if(q[i].op==0)
            scanf("%lld%lld",&q[i].t[0],&q[i].t[1]);
        else
            if(q[i].op==1)
                scanf("%lld",&q[i].t[0]);
        else
            scanf("%lld%lld",&q[i].t[0],&q[i].t[1]);
    }
    lisan();

    /*printf("\n");
    for(int i=1;i<=n;++i)
        printf("hhh %d %lld %lld\n",q[i].op,q[i].t[0],q[i].t[1]);
    printf("\n");*/

    for(int i=1;i<=n;++i)
    {

        if(q[i].op==0)
        {
            Tsh.add(q[i].t[0],q[i].t[1],1,mm,1);
            Txi.add(q[i].t[0],q[i].t[1],1,mm,1);
            val[q[i].t[0]]=q[i].t[1];
        }
        else
            if(q[i].op==1)
            {
                Tsh.add(q[i].t[0],-val[q[i].t[0]],1,mm,1);
                Txi.add(q[i].t[0],-val[q[i].t[0]],1,mm,1);
            }
        else
        {
            int lca;
            if(q[i].t[0]<=q[i].t[1])
                lca=dui[Tsh.qqmax(q[i].t[0],q[i].t[1],1,mm,1)];
            else
                lca=dui[Tsh.qqmax(q[i].t[1],q[i].t[0],1,mm,1)];
            //printf("lca=%d\n",lca);
            printf("%d\n",get(q[i].t[0])+get(q[i].t[1])-2*get(lca) );//printf("i=%d\n",i);
        }
    }
}
T3

 

昨天这个题我感觉极其难,反正考试全都打了暴力...

但是 做难事必有所得 --------某建老师

做难题才有提升...

posted @ 2017-10-07 08:18  A_LEAF  阅读(147)  评论(0编辑  收藏  举报