首页 > 其他 > 详细

7.12总结

时间:2019-07-12 21:47:41      阅读:112      评论:0      收藏:0      [点我收藏+]

7.12总结

得分情况

估分:0+50+100

实际:0+30+100

第二题打炸了

T1

题目大意

神犇家门口种了一棵苹果树。苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条。由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色。我们用一个1到N之间的正整数来表示一种颜色。树上一共有N个苹果。每个苹果都被编了号码,号码为一个1到N之间的正整数。我们用0代表树根。只会有一个苹果直接连到树根。

有许许多多的人来神犇家里膜拜神犇。可神犇可不是随便就能膜拜的。前来膜拜神犇的人需要正确回答一个问题,才能进屋膜拜神犇。这个问题就是,从树上编号为N的苹果出发,由树枝走到编号为N的苹果,路径上经过的苹果一共有多少种不同的颜色(包括苹果u和苹果v的颜色)?不过神犇注意到,有些来膜拜的人患有色盲症。具体地说,一个人可能会认为颜色a就是颜色b,那么他们在数苹果的颜色时,如果既出现了颜色a的苹果,又出现了颜色b的苹果,这个人只会算入颜色b,而不会把颜色a算进来。

神犇是一个好人,他不会强人所难,也就会接受由于色盲症导致的答案错误(当然答案在色盲环境下也必须是正确的)。不过这样神犇也就要更改他原先数颜色的程序了。虽然这对于神犇来说是小菜一碟,但是他想考验一下你。你能替神犇完成这项任务吗?
n<=50000

m<=100000

比赛的时候猜到是把询问离线跑树上莫队

然而…

我不会树上莫队呀

GG

T2

题目大意

神犇最近闲来无事,于是就思考哲学,研究数字之美。在神犇看来,如果一个数的各位能够被分成两个集合,而且这两个集合里的数的和相等,那么这个数就是优美的(具体原因就只有神犇才知道了)。现在神犇在思考另一个问题,在区间[A,B]中有多少个数是优美的?这个问题对于神犇来说很简单,相信对于你来说也不难。

对于100%的数据,1<=A<=B<=10^9。

正解

由于A,B的范围只有10^9,所以估计不是常规的数位dp(反正我这题也不会dp)

容易发现,最多只有9个数字,要把它们分成两个和相等的集合。那么方案总数肯定是比较小的。所以我们可以先把这种选择两个集合的方案求出来,再用暴力或其他手段求这种方案在1~n的范围有多少种。

先考虑如何求合法的数字集

方法一

枚举一个数字集,设总和为sum,用背包判断是否能从从中选出若干个数使和为sum/2。

用挡板法可以算出全部数字集的个数应该为\(\sum_{i=1}^9{C_{10+i-1}^{10-1}}\)

不到10^5个,是可以接受的

方法二(我的方法)

显然可以折半搜索,找出和为s的数字集,两两组合,然后去重

然而我折半搜索打错了。

一开始以为两边的数字集最多只有5个数字

然而对于{1,1,1,1,1,1,1,1};{8}这种,最多可以有8个数字

那么求出合法数字集之后,若数字集大小小于n,就随便排列。若数字集大小等于n,可以先枚举开头几位防止越界,剩下的用排列公式算。

注意不能有前导零

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct kk
{
    int num[11];
};

int L,R,i,j,x,ans,s,k,cnt,sum;
kk a[500005];
int b[15],num[10][2];
int jc[10];
int l[100005][10],next[100005],last[105],tot;

void insert(int x)
{
    tot++;
    for (int i=0;i<=b[0];i++)
    l[tot][i]=b[i];
    next[tot]=last[x];
    last[x]=tot;
}

void dfs(int x,int last,int s)
{
    if ((x>8)||(s>45)) return;
    insert(s);
    for (int i=last;i<=9;i++)
    {
        b[++b[0]]=i;
        dfs(x+1,i,s+i);
        b[0]--;
    }
}

int dg(int x,int len,int islow,int begin)
{
    int i;
    if (islow)
    {
        len=len-x+1;
        int s;
        s=jc[len];
        for (i=1;i<=cnt;i++)
        s=s/jc[num[i][1]];
        return s;
    }
    if (x>len)
    {
        return 1;
    }
    else
    {
        int s=0;
        for (int i=1;i<=cnt;i++)
        {
            if ((num[i][1]!=0)&&((islow==1)||(num[i][0]<=b[x]))&&((begin)||(num[i][0]>=1)))
            {
                num[i][1]--;
                if (num[i][0]==b[x])
                {
                    s+=dg(x+1,len,islow,1);
                }
                else
                {
                    s+=dg(x+1,len,1,1);
                }
                num[i][1]++;
            }
        }
        return s;
    }
}

int js(int up,int len)
{
    int x=up,s,i;
    b[0]=0;
    while (x>0)
    {
        b[++b[0]]=x%10;
        x/=10;
    }
    if (len>b[0]) return 0;
    if (len<b[0])
    {
        if (num[1][0]==0)
        {
            s=jc[len-num[1][1]];
            for (int i=2;i<=cnt;i++)
            s=s/jc[num[i][1]];
            s=s*jc[len-1]/jc[num[1][1]]/jc[len-1-num[1][1]];
        }
        else
        {
            s=jc[len];
            for (int i=1;i<=cnt;i++)
            s=s/jc[num[i][1]];
        }
        return s;
    }
    for (i=1;i<=b[0]/2;i++)
    swap(b[i],b[b[0]-i+1]);
    s=dg(1,len,0,0);
    return s;
}

int comp(kk a,kk b)
{
    if (a.num[0]<b.num[0]) return 1;
    if (a.num[0]>b.num[0]) return 0;
    for (int i=1;i<=a.num[0];i++)
    {
        if (a.num[i]<b.num[i]) return 1;
        if (a.num[i]>b.num[i]) return 0;
    }
    return 0;
}

int issame(kk a,kk b)
{
    if (a.num[0]!=b.num[0]) return 0;
    for (int i=1;i<=a.num[0];i++)
    {
        if (a.num[i]!=b.num[i]) return 0;
    }
    return 1;
}

int main()
{
    freopen("read.in","r",stdin);
    jc[0]=1;
    for (i=1;i<=9;i++)
    jc[i]=jc[i-1]*i;
    scanf("%d%d",&L,&R);
    R=min(R,999999999);
    dfs(0,0,0);
    for (x=1;x<=45;x++)
    {
        for (i=last[x];i>=1;i=next[i])
        {
            for (j=last[x];j>=1;j=next[j])
            {
                if ((j>i)||(l[i][0]+l[j][0]>9)) continue;
                sum++;
                a[sum].num[0]=0;
                for (k=1;k<=l[i][0];k++)
                a[sum].num[++a[sum].num[0]]=l[i][k];
                for (k=1;k<=l[j][0];k++)
                a[sum].num[++a[sum].num[0]]=l[j][k];
                sort(a[sum].num+1,a[sum].num+1+a[sum].num[0]);
            }
        }
    }
    sort(a+1,a+1+sum,comp);
    for (i=1;i<=sum;i++)
    {
        if (issame(a[i],a[i-1])) continue;
        cnt=1;
        num[1][0]=a[i].num[1];
        num[1][1]=1;
        for (k=2;k<=a[i].num[0];k++)
        {
            if (a[i].num[k]!=a[i].num[k-1])
            {
                cnt++;
                num[cnt][0]=a[i].num[k];
                num[cnt][1]=1;
            }
            else
            {
                num[cnt][1]++;
            }
        }
        ans=ans+js(R,a[i].num[0]);
        ans=ans-js(L-1,a[i].num[0]);
    }
    printf("%d",ans);
}

水法

分块打表。

每10^6记录一次答案。

T3

题目大意

深绘里一直很讨厌雨天。

灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。

虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连

根拔起,以及田地里的粮食被弄得一片狼藉。

无奈的深绘里和村民们只好等待救济粮来维生。

不过救济粮的发放方式很特别。

首先村落里的一共有n 座房屋,并形成一个树状结构。然后救济粮分m 次发放,每次选择

两个房屋(x,y),然后对于x 到y 的路径上(含x 和y) 每座房子里发放一袋z 类型的救济粮。

然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。

对于100% 的数据,1 <= n;m <= 100000; 1 <= a, b, x, y <= n; 1 <= z <= 10^9

一眼树上差分+线段树合并。

对于修改操作(x,y,z),把+z标记打在x,y上面,把-z标记打在lca和fa[lca]上面。

把每个节点的儿子的线段树合并起来就是这个节点的值。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct qy
{
    int ch[2],masum,ma;
};

int n,m,i,j,k;
int x,y,z,xx;
int l[400005],next[400005],last[100005],tot,depth[100005];
int son[200005],nextt[200005],lastt[200005],tott;
int fa[100005][20];
qy tree[5000005];
int root[100005],cnt;
int ans[100005];
int pool[5000005];

void insert(int x,int y)
{
    tot++;
    l[tot]=y;
    next[tot]=last[x];
    last[x]=tot;
}

void insertt(int x,int y)
{
    tott++;
    son[tott]=y;
    nextt[tott]=lastt[x];
    lastt[x]=tott;
}

void build(int x)
{
    for (int i=1;i<=19;i++)
    fa[x][i]=fa[fa[x][i-1]][i-1];
    for (int i=last[x];i>=1;i=next[i])
    {
        if (depth[l[i]]==0)
        {
            depth[l[i]]=depth[x]+1;
            fa[l[i]][0]=x;
            insertt(x,l[i]);
            build(l[i]);
        }
    }
}

int lca(int x,int y)
{
    if (depth[x]<depth[y]) swap(x,y);
    for (int i=19;i>=0;i--)
    {
        if (depth[fa[x][i]]>=depth[y])
        x=fa[x][i];
    }
    if (x==y) return x;
    for (int i=19;i>=0;i--)
    {
        if (fa[x][i]!=fa[y][i])
        {
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    return fa[x][0];
}

int newnode()
{
    return pool[pool[0]--];
}

void recycle(int x)
{
    tree[x].ch[0]=tree[x].ch[1]=tree[x].ma=tree[x].masum=0;
    pool[++pool[0]]=x;
}

int merge(int k1,int k2,int l,int r)
{
    if ((k1==0)||(k2==0)) return k1+k2;
    int k3=newnode();
    if (l==r)
    {
        tree[k3].masum=tree[k1].masum+tree[k2].masum;
        tree[k3].ma=l;
    }
    else
    {
        int mid=(l+r)/2;
        tree[k3].ch[0]=merge(tree[k1].ch[0],tree[k2].ch[0],l,mid);
        tree[k3].ch[1]=merge(tree[k1].ch[1],tree[k2].ch[1],mid+1,r);
        if (tree[tree[k3].ch[0]].masum>=tree[tree[k3].ch[1]].masum)
        {
            tree[k3].masum=tree[tree[k3].ch[0]].masum;
            tree[k3].ma=tree[tree[k3].ch[0]].ma;
        }
        else
        {
            tree[k3].masum=tree[tree[k3].ch[1]].masum;
            tree[k3].ma=tree[tree[k3].ch[1]].ma;
        }
    }
    recycle(k1);
    recycle(k2);
    return k3;
}

void modify(int k,int l,int r,int x,int y)
{
    if (l==r)
    {
        tree[k].masum+=y;
        tree[k].ma=l;
    }
    else
    {
        int mid=(l+r)/2;
        if (x<=mid)
        {
            if (tree[k].ch[0]==0)
            tree[k].ch[0]=newnode();
            modify(tree[k].ch[0],l,mid,x,y);
        }
        else
        {
            if (tree[k].ch[1]==0)
            tree[k].ch[1]=newnode();
            modify(tree[k].ch[1],mid+1,r,x,y);
        }
        if (tree[tree[k].ch[0]].masum>=tree[tree[k].ch[1]].masum)
        {
            tree[k].masum=tree[tree[k].ch[0]].masum;
            tree[k].ma=tree[tree[k].ch[0]].ma;
        }
        else
        {
            tree[k].masum=tree[tree[k].ch[1]].masum;
            tree[k].ma=tree[tree[k].ch[1]].ma;
        }
    }
}

void dg(int x)
{
    for (int i=lastt[x];i>=1;i=nextt[i])
    {
        dg(son[i]);
    }
    root[x]=newnode();
    for (int i=lastt[x];i>=1;i=nextt[i])
    {
        root[x]=merge(root[x],root[son[i]],1,1000000000);
    }
    for (int i=last[x];i>=1;i=next[i])
    {
        if (l[i]>0)
        {
            modify(root[x],1,1000000000,l[i],1);
        }
        else
        {
            modify(root[x],1,1000000000,-l[i],-1);
        }
    }
    if (tree[root[x]].masum>0)
        ans[x]=tree[root[x]].ma;
    else
        ans[x]=0;
}

int read()
{
    int s=0;char ch=getchar();
    while ((ch<'0')||(ch>'9')) ch=getchar();
    while ((ch>='0')&&(ch<='9'))
    {
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s;
}

int main()
{
    freopen("read.in","r",stdin);
    freopen("write.out","w",stdout);
    for (i=1;i<=5000000;i++)
    {
        pool[i]=5000000-i+1;
    }
    pool[0]=5000000;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n-1;i++)
    {
        x=read();
        y=read();
        insert(x,y);
        insert(y,x);
    }
    depth[1]=1;
    build(1);
    tot=0;
    memset(last,0,sizeof(last));
    for (i=1;i<=m;i++)
    {
        x=read();
        y=read();
        z=read();
        xx=lca(x,y);
        insert(xx,-z);
        if (fa[xx][0]!=0)
        insert(fa[xx][0],-z);
        
        insert(x,z);//顺序不能换 
        insert(y,z);
    }
    dg(1);
    for (i=1;i<=n;i++)
    printf("%d\n",ans[i]);
}

7.12总结

原文:https://www.cnblogs.com/leason-lyx/p/11178087.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!