zoukankan      html  css  js  c++  java
  • 7.12总结

    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
    ",ans[i]);
    }
    
  • 相关阅读:
    Java注解入门
    两种求素数
    几个经典的递归小程序
    Java8新特性——接口的默认方法和类方法
    SSH框架总结
    初识SSH框架
    Mybatis中DAO层接口没有写实现类,Mapper中的方法和DAO接口方法是怎么绑定到一起的
    使用SQL查询所有数据库名和表名
    mybatis中#{}和${}的区别
    SOCKET, TCP/UDP, HTTP, FTP 浅析
  • 原文地址:https://www.cnblogs.com/leason-lyx/p/11178087.html
Copyright © 2011-2022 走看看