test20190305

  • 上午考试,是 \(SCOI\ 2016\ Day\ 1\) 的题目.

背单词

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int MAXN=1e5+10,MAXL=510010,Siz=26;
int N;
int idx,dfn,tot;
ll ans;
int ch[MAXL][Siz];
int val[MAXL];
void ins(char *s,int n,int v)
{
    int u=0;
    for(int i=n-1; i>=0; --i)
        {
            int k=s[i]-'a';
            if(!ch[u][k])
                ch[u][k]=++idx;
            u=ch[u][k];
        }
    val[u]=v;
}
int cnt=0,head[MAXN],to[MAXN<<1],nx[MAXN<<1];
int siz[MAXN];
inline void addedge(int u,int v)
{
    ++cnt;
    to[cnt]=v;
    nx[cnt]=head[u];
    head[u]=cnt;
}
void bg(int u,int lst)
{
    if(val[u])
        {
            addedge(lst,val[u]);
            lst=val[u];
        }
    for(int k=0; k<Siz; ++k)
        {
            if(!ch[u][k])
                continue;
            bg(ch[u][k],lst);
        }
}
void getsiz(int u)
{
    siz[u]=1;
    for(int i=head[u];i;i=nx[i])
        {
            int v=to[i];
            getsiz(v);
            siz[u]+=siz[v];
        }
}
typedef pair<int,int> pii;
int vis[MAXN];
pii tmp[MAXN];
stack<int> stk;
void dfs(int u,int fa)
{
    int pos=0;
    vis[u]=++tot;
    ans+=vis[u]-vis[fa];
    for(int i=head[u];i;i=nx[i])
        {
            int v=to[i];
            tmp[++pos]=make_pair(-siz[v],v);
        }
    sort(tmp+1,tmp+1+pos);
    for(int i=1;i<=pos;++i)
        stk.push(tmp[i].second);
    while(pos--)
        {
            int v=stk.top();
            stk.pop();
            dfs(v,u);
        }
}
void solve()
{
    bg(0,0);
    getsiz(0);
    dfn=0;
    dfs(0,0);
    cout<<ans<<endl;
}
char buf[MAXL];
int main()
{
    freopen("word.in","r",stdin);
    freopen("word.out","w",stdout);
    int N=read();
    for(int i=1; i<=N; ++i)
        {
            scanf("%s",buf);
            int n=strlen(buf);
            ins(buf,n,i);
        }
    solve();
    return 0;
}

幸运数字

  • 标算应该是 \(O(nlogn*60+Q*60^2)\) 的点分治...难得写离线挂询问,就写了 \(O(Qlogn*logn*60^2)\) 的树剖暴力搞...(其实跑不满)没开 \(O2\) ,被卡了一个点. \(ljq\) 同样的做法却 \(A\) 了,只跑了我的一半时间...
  • 树剖的做法比较显然,直接用线段树维护区间内所有数字的线性基,合并时暴力合并,因为数字不会占满 \(60\) 位,合并时就跑不满 \(60*60\) ,优化一下常数是能过的.
  • 点分治的做法比较类似,求出重心到各个点路径上数字的线性基后,也是暴力合并线性基,但只在询问时合并.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int MAXN=2e4+10;
int n;
int cnt=0,head[MAXN],to[MAXN<<1],nx[MAXN<<1];
void addedge(int u,int v)
{
    ++cnt;
    to[cnt]=v;
    nx[cnt]=head[u];
    head[u]=cnt;
    swap(u,v);
    ++cnt;
    to[cnt]=v;
    nx[cnt]=head[u];
    head[u]=cnt;
}
ll w[MAXN];
int idx=0,fa[MAXN],dfn[MAXN],rnk[MAXN],siz[MAXN],mxson[MAXN],top[MAXN],dep[MAXN];
void dfs1(int u,int Fa)
{
    siz[u]=1;
    fa[u]=Fa;
    dep[u]=dep[Fa]+1;
    for(int i=head[u];i;i=nx[i])
        {
            int v=to[i];
            if(v==Fa)
                continue;
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[v]>siz[mxson[u]])
                mxson[u]=v;
        }
}
void dfs2(int u,int tp)
{
    ++idx;
    dfn[u]=idx;
    rnk[idx]=u;
    top[u]=tp;
    if(mxson[u])
        dfs2(mxson[u],tp);
    for(int i=head[u];i;i=nx[i])
        {
            int v=to[i];
            if(v==fa[u] || v==mxson[u])
                continue;
            dfs2(v,v);
        }
}
namespace SEG{
    struct node{
    int l,r;
    ll v[62];
    void init(){memset(v,0,sizeof v);}
    node(){init();}
    void ins(ll x)
        {
            for(int i=61;i>=0;--i)
                {
                    if((x>>i) & 1)
                        {
                            if(!v[i])
                                {
                                    v[i]=x;
                                    break;
                                }
                            x^=v[i];
                        }
                }
        }
    ll mxv()
        {
            ll ans=0;
            for(int i=61;i>=0;--i)
                if((ans^v[i])>ans)
                    ans^=v[i];
            return ans;
        }
    friend node operator + (const node &a,const node &b)
        {
            node res=a;
            for(int i=0;i<=61;++i)
                if(b.v[i])
                    res.ins(b.v[i]);
            return res;
        }
    }Tree[MAXN<<2];
    node res;
#define root Tree[o]
#define lson Tree[o<<1]
#define rson Tree[o<<1|1]
    inline void pushup(int o)
    {
        int l=root.l,r=root.r;
        root=lson+rson;
        root.l=l,root.r=r;
    }
    void BuildTree(int o,int l,int r)
    {
        root.l=l,root.r=r;
        if(l==r)
            {
                root.ins(w[rnk[l]]);
                return;
            }
        int mid=(l+r)>>1;
        BuildTree(o<<1,l,mid);
        BuildTree(o<<1|1,mid+1,r);
        pushup(o);
    }
    void query(int o,int L,int R)
        {
            int l=root.l,r=root.r;
            if(l>R || L>r)
                return;
            if(L<=l && r<=R)
                {
                    res=res+root;
                    return;
                }
            int mid=(l+r)>>1;
            if(L<=mid)
                query(o<<1,L,R);
            if(R>mid)
                query(o<<1|1,L,R);
        }
}
using namespace SEG;
void solve(int x,int y)
{
    res.init();
    while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])
                swap(x,y);
            query(1,dfn[top[x]],dfn[x]);
            x=fa[top[x]];
        }
    if(dep[x]<dep[y])
        swap(x,y);
    query(1,dfn[y],dfn[x]);
    printf("%lld\n",res.mxv());
}
int main()
{
    freopen("lucky.in","r",stdin);
    freopen("lucky.out","w",stdout);
    n=read();
    int Q=read();
    for(int i=1;i<=n;++i)
        scanf("%lld",&w[i]);
    for(int i=1;i<n;++i)
        {
            int u=read(),v=read();
            addedge(u,v);
        }
    dfs1(1,0);
    dfs2(1,1);
    BuildTree(1,1,n);
    while(Q--)
        {
            int x=read(),y=read();
            solve(x,y);
        }
    return 0;
}

萌萌哒

  • 用并查集维护,钦定了相同的位置被归在一个联通块中,若共有 \(b\) 个联通块,最后答案显然为 \(9*10^{b-1}\).
  • 场上做法:对每个限制条件暴力合并,时间复杂度为 \(O(n^2)\) .获得 \(30\) 分好成绩.
  • 要注意到限制条件都是限制一段连续区间,而不是离散的 \(n^2\) 个限制.可以在并查集上用上 \(ST\) 表的思想.
  • \(fa[k][i]\) 表示从位置 \(i\) 开始的 \(2^k\) 个元素的并查集代表元素.也就是说,若 \(fa[k][i]=fa[k][j]\) ,则 \([i,i+2^k-1]\)\([j,j+2^k-1]\) 这两段区间元素是相等的.
  • 这个合并是可以重叠的,合并区间时合并前半段和后半段即可.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int P=1e9+7;
inline int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
        {
            if(b&1)
                res=mul(res,a);
            a=mul(a,a);
            b>>=1;
        }
    return res;
}
const int MAXK=20,MAXN=1e5+10;
int fa[MAXK][MAXN];
int Find(int k,int x)
{
    if(x==fa[k][x])
        return x;
    return fa[k][x]=Find(k,fa[k][x]);
}
void Merge(int k,int x,int y)//合并[x,x+2^k-1],[y,y+2^k-1]
{
    int u=Find(k,x),v=Find(k,y);
    if(u!=v)
        {
            fa[k][u]=v;
            if(!k)
                return;
            Merge(k-1,x,y);
            Merge(k-1,x+(1<<(k-1)),y+(1<<(k-1)));
        }
}
int n,m;
int main()
{
    n=read(),m=read();
    for(int k=0;k<MAXK;++k)
        for(int i=1;i<=n;++i)
            fa[k][i]=i;
    for(int i=1;i<=m;++i)
        {
            int L1=read(),R1=read(),L2=read(),R2=read();
            int k=floor(log2(R1-L1+1));
            Merge(k,L1,L2);
            Merge(k,R1-(1<<k)+1,R2-(1<<k)+1);
        }
    int blocks=0;
    for(int i=1;i<=n;++i)
        if(fa[0][i]==i)
            ++blocks;
    int ans=mul(9,fpow(10,blocks-1));
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/jklover/p/10476102.html
今日推荐