FR #13题解

Posted on 2017-02-20 14:28  ziliuziliu  阅读(141)  评论(0编辑  收藏  举报

A.

  有点像学军中学的一道NOIP模拟赛的题。因为插入的顺序唯一,然后就完了。。。

     具体操作是在线段树上二分,然后区间赋值1等等。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxv 100500
#define maxe 200500
using namespace std;
int n,q,x,y,g[maxv],nume=1,w[maxv],fw[maxv],dis[maxv],cnt=0,tot=0,anc[maxv][20],val[maxv];
int ls[maxv<<2],rs[maxv<<2],lazy[maxv<<2],sum[maxv<<2],root,tr_root;
int t=0;
struct status
{
    int id,val;
    status (int id,int val):id(id),val(val) {}
    status () {}
};
vector <status> v[maxv];
struct edge
{
    int v,nxt;
}e[maxe];
bool cmp(status x,status y) {return x.val<y.val;}
void addedge(int u,int v)
{
    e[++nume].v=v;e[nume].nxt=g[u];
    g[u]=nume;
}
void dfs1(int x)
{
    val[x]=x;
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (v!=anc[x][0])
        {
            anc[v][0]=x;dis[v]=dis[x]+1;
            dfs1(v);
            val[x]=min(val[x],val[v]);    
        }
    }
}
void dfs2(int x)
{
    for (int i=g[x];i;i=e[i].nxt)
    {
        int vs=e[i].v;
        if (vs==anc[x][0]) continue;
        v[x].push_back(status(vs,val[vs]));
    }
    sort(v[x].begin(),v[x].end(),cmp);
    for (int i=0;i<v[x].size();i++) dfs2(v[x][i].id);
    w[x]=++cnt;fw[cnt]=x;
}
void build(int &now,int left,int right)
{
    now=++tot;sum[now]=lazy[now]=0;
    if (left==right) return;
    int mid=(left+right)>>1;
    build(ls[now],left,mid);
    build(rs[now],mid+1,right);
}
void pushdown(int now,int left,int right)
{
    if (!lazy[now]) return;
    lazy[ls[now]]=lazy[rs[now]]=1;lazy[now]=0;
    int mid=(left+right)>>1;
    sum[ls[now]]=mid-left+1;sum[rs[now]]=right-mid;
}
int modify1(int now,int left,int right,int k)
{
    pushdown(now,left,right);
    if (left==right) {sum[now]=1;return fw[left];}
    int mid=(left+right)>>1,r=(mid-left+1-sum[ls[now]]),ret;
    if (k>r) sum[ls[now]]=mid-left+1,lazy[ls[now]]=1;
    if (k>r) ret=modify1(rs[now],mid+1,right,k-r);
    else ret=modify1(ls[now],left,mid,k);
    sum[now]=sum[ls[now]]+sum[rs[now]];
    return ret;
}
int ask(int now,int left,int right,int pos)
{
    if (!pos) return 0;
    pushdown(now,left,right);
    if (left==right) return sum[now];
    int mid=(left+right)>>1;
    if (pos<=mid) return ask(ls[now],left,mid,pos);
    else return ask(rs[now],mid+1,right,pos);
}
void modify2(int now,int left,int right,int pos)
{
    pushdown(now,left,right);
    if (left==right) {sum[now]=0;return;}
    int mid=(left+right)>>1;
    if (pos<=mid) modify2(ls[now],left,mid,pos);
    else modify2(rs[now],mid+1,right,pos);
    sum[now]=sum[ls[now]]+sum[rs[now]];
}
void work2()
{
    int reg=y;
    for (int e=19;e>=0;e--)
    {
        int ret=ask(root,1,n,w[anc[y][e]]);
        if (ret) y=anc[y][e];
    }
    modify2(root,1,n,w[y]);
    printf("%d\n",dis[reg]-dis[y]);
}
int main()
{
    scanf("%d%d",&n,&q);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        if (!x) tr_root=i;
        else {addedge(x,i);addedge(i,x);}
    }
    dfs1(tr_root);dfs2(tr_root);
    for (int e=1;e<=19;e++)
        for (int i=1;i<=n;i++)
            anc[i][e]=anc[anc[i][e-1]][e-1];
    build(root,1,n);
    for (int i=1;i<=q;i++)
    {
        scanf("%d%d",&x,&y);
        if (x==1) printf("%d\n",modify1(root,1,n,y));
        else work2();
    }
    return 0;
}

B.

  本来以为要用什么奇怪的自动机等等等等,然后。。。。

      设这个数位置是n。奇数长度?a[n]!=a[n-2]。否则?a[n]!=a[n-1]。

      然后数位dp一波就完了。。。

      注意判0。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long a,b,dp[20][10][10],ret=0,bit[20];
void getbit(long long x)
{
    ret=0;
    while (x)
    {
        bit[++ret]=x%10;
        x/=10;
    }
}
long long dfs(long long now,long long pre2,long long pre1,bool flag)
{
    if (!now) return 1;
    if ((!flag) && (pre2!=-1) && (pre1!=-1) && (dp[now][pre2][pre1])) return dp[now][pre2][pre1];
    long long ret=0,up=flag?bit[now]:9;
    for (long long i=0;i<=up;i++)
    {
        if ((i!=pre2) && (i!=pre1))
            ret+=dfs(now-1,pre1,i,flag && (i==bit[now]));
    }
    if ((!flag) && (pre2!=-1) && (pre1!=-1)) dp[now][pre1][pre2]=ret;
    return ret;
}
long long ask(long long x)
{
    if (x==-1) return 0;
    getbit(x);long long ans=0;
    for (long long i=1;i<=ret-1;i++)
        for (long long j=1;j<=9;j++)
            ans+=dfs(i-1,-1,j,0);
    for (long long i=1;i<=bit[ret]-1;i++)
        ans+=dfs(ret-1,-1,i,0);
    ans+=dfs(ret-1,-1,bit[ret],1);
    return ans;
}
int main()
{
    scanf("%lld%lld",&a,&b);
    if (!a) {a++;printf("%lld\n",ask(b)-ask(a-1)+1);}
    else printf("%lld\n",ask(b)-ask(a-1));
    return 0;
}

C.

  m>n?肯定多解。。。

     m<n?废话。。。

     m=n?环套树。。。然后直接按环上解方程就行了。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxv 100500
#define maxe 1000050
using namespace std;
int n,m,x,y,c[maxv],g[maxv],nume=1,val[maxe],d[maxv];
int top=0,flag2,flag3;
bool vis[maxv],rol[maxv],flag1,flag4;
struct edge
{
    int v,nxt;
}e[maxe];
struct status
{
    int id,id1,id2,val;
    status (int id,int id1,int id2,int val):id(id),id1(id1),id2(id2),val(val) {}
    status () {}
}s[maxv];
bool cmp(status x,status y) {return x.id<y.id;}
void addedge(int u,int v)
{
    e[++nume].v=v;e[nume].nxt=g[u];
    g[u]=nume;
}
void dfs1(int x,int fath,int fath_e)
{
    int ret=0;
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (v==fath) continue;
        dfs1(v,x,i);ret-=val[i>>1];
    }
    val[fath_e>>1]=c[x]+ret;
}
void dfs2(int x,int fath_e)
{
    vis[x]=true;
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if ((vis[v]) && (i!=(fath_e^1)))
        {
            s[++top]=status(x,i>>1,fath_e>>1,c[x]);
            flag1=1;flag2=v;flag3=i;rol[x]=true;
            return;
        }
        if (vis[v]) continue;
        dfs2(v,i);
        if (flag1)
        {
            if (flag4) return;
            rol[x]=true;
            if (x!=flag2) s[++top]=status(x,i>>1,fath_e>>1,c[x]);
            else {s[++top]=status(x,i>>1,flag3>>1,c[x]);flag4=1;}
            return;
        }
    }
    return;
}
void work1()
{
    dfs1(1,1,0);
    for (int i=1;i<=m;i++) printf("%d\n",val[i]<<1);
    return;
}
void work2()
{
    for (int i=1;i<=n;i++)
        if (d[i]==1)
            {dfs2(i,0);break;}
    if (!(top&1)) {printf("0\n");return;}
    for (int i=1;i<=n;i++)
    {
        if (!rol[i]) continue;
        for (int j=g[i];j;j=e[j].nxt)
        {
            int v=e[j].v;
            if (rol[v]) continue;
            dfs1(v,i,j);c[i]-=val[j>>1];
        }
    }
    int ret=0;
    for (int i=1;i<=top-1;i++)
    {
        if (i&1) ret+=c[s[i].id];
        else ret-=c[s[i].id];
    }
    val[s[1].id1]=(ret+c[s[top].id])/2;
    for (int i=1;i<=top-1;i++)
        val[s[i].id2]=c[s[i].id]-val[s[i].id1];
    for (int i=1;i<=m;i++) printf("%d\n",val[i]<<1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&c[i]);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        addedge(x,y);addedge(y,x);
        d[x]++;d[y]++;
    }
    if (m>n) printf("0\n");
    else if (m<n) work1();
    else work2();
    return 0;
}

怎么说呢?。。。三道题都是,只要点出了它的核心都很简单。那么重点就是那一点点思维。