猴猴最喜欢在树上玩耍,一天猴猴又跳上了一棵树,这棵树有N个苹果,每一个苹果有一个编号,分
别为0~N-1,它们之间由N-1个树枝相连,猴猴能够从树枝的一端爬到树枝的另外一端,因此猴猴可
以从任意一个苹果的位置出发爬到任意猴猴想去的苹果的位置。猴猴开始在编号为K的苹果的位
置,而且把这个苹果吃了,以后每一天猴猴都要去吃一个苹果,可是树上那么多苹果吃哪一个呢?
猴猴想到本身去吃苹果时必定会把路上遇到的苹果都吃掉,因而猴猴决定去吃能让本身这天吃的
苹果数量最多的那个苹果,若是有多个苹果知足条件,猴猴就会去吃这些中编号最小的苹果,那
么猴猴会按照什么顺序吃苹果呢?c++
对于30%的数据:N<=100
对于60%的数据:N<=1000
对于100%的数据:N<=50000,0<=K<Ngit
分析:60%的分数都只要暴力模拟就行了,每次找最长的走过去;数组
考虑一个性质:走过的点的权值会消失,那么每次移动到终点位置和每次都从初始给定的点出发的答案都同样的,并且终点必定会是叶子节点;ide
那么咱们设初始节点为根节点,先进行一遍dfs,把全部叶子节点记录下来,按照深度排序;spa
而后让每一个点沿着父亲往上跳,每跳一步答案增长1,遇到根节点或者走过的节点就中止(遇到走过的点说明上面的权值都没有了code
而后把叶子节点按答案从小到大输出(看完题解以为智商被人按在地上摩擦了)blog
#include<bits/stdc++.h> using namespace std; namespace knife_rose{ #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define mid ((l+r)>>1) inline int read() { int x=0;char ch,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } const int N=1e5+10; int n,rt; int head[N],cnt; struct point { int nxt,to; point(){} point(const int &nxt,const int &to):nxt(nxt),to(to){} }a[N<<1]; inline void link(int x,int y) { a[++cnt]=(point){head[x],y};head[x]=cnt; a[++cnt]=(point){head[y],x};head[y]=cnt; } int f[N],dep[N],lea[N],num,sum[N]; bool vis[N]; inline void dfs(int now,int fa) { f[now]=fa; dep[now]=dep[fa]+1; bool flag=0; for(int i=head[now];i;i=a[i].nxt) { int t=a[i].to; if(t==fa) continue; flag=1; dfs(t,now); } if(!flag) lea[++num]=now; } inline bool cmp1(int a,int b)//深度排序,深度相同按编号大小 { return dep[a]^dep[b]?dep[a]>dep[b]:a<b; } inline bool cmp2(int a,int b)//答案排序 { return sum[a]^sum[b]?sum[a]>sum[b]:a<b; } signed main() { n=read(),rt=read(); for(int x,i=1;i<n;++i) { x=read(); link(x,i); } dfs(rt,rt); sort(lea+1,lea+num+1,cmp1); vis[rt]=1; for(int i=1;i<=num;++i) { int now=lea[i]; while(!vis[now]) { ++sum[lea[i]]; vis[now]=1; now=f[now]; } } sort(lea+1,lea+num+1,cmp2); printf("%d\n",rt); for(int i=1;i<=num;++i) printf("%d\n",lea[i]); return 0; } } signed main() { return knife_rose::main(); }
猴猴最爱吃香蕉了。天天猴猴出门都会摘不少不少的香蕉,每一个香蕉都有一个甜度,猴猴不必定
要把全部的香蕉都吃掉,猴猴天天都有一个心情值K,猴猴但愿当天吃的香蕉知足这么一个条件,
这些香蕉的甜度乘积刚好等于K,可是猴猴并不知道有多少种方法,因而猴猴把这个问题交给你。排序
对于30%的数据:n,K<=100
对于60%的数据:n<=1000,K<=10000
对于100%的数据:n<=1000,K<=100000000,D<=20(D是数据组数get
30%:我也没想出来咋拿30分(it
60%:题目是个很明显的背包,可是因为是乘法因此有一些特殊之处:只有k的约数才能做为转移,因此咱们能够筛出来k的约数,是根号量级的;
统计答案须要二分查找,复杂度O(D×n√k×log(√k))
100%:其实上面那个作法就是100分,然而官方题解也是这么给的,可是很明显复杂度不对啊qwq
然而机房里某位巨佬想出了复杂度更优秀的作法,%%%szx
先对k进行质因数分解,根据每一个质因子个数将答案压缩成一个多进制状态,而后将每一个a[i]也压缩成对应的多进制状态进行转移,能够发现质因子个数不多,不超过30个
设t是多进制状态最大值
复杂度为O(√k+n√a[i]+nt)
#include<bits/stdc++.h> using namespace std; namespace knife_rose{ #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define mid ((l+r)>>1) inline int read() { int x=0;char ch,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } const int N=1e4+10,p=1e9+7; int tyx,n,m,ed,tot; int a[N]; int st[40],sum[40],top; int git[40],c[40],s[N][40]; int g[N],f[1000010]; bool vis[N]; inline void clear() { memset(g,0,sizeof(g)); memset(f,0,sizeof(f)); memset(sum,0,sizeof(sum)); memset(s,0,sizeof(s)); memset(vis,0,sizeof(vis)); top=0; } signed main() { tyx=read(); while(tyx--) { clear(); n=read(),m=read(); for(int i=1;i<=n;++i) a[i]=read(); int qr=sqrt(m),tmp=m; for(int i=2;i<=qr;++i) { if(tmp%i==0) { st[++top]=i; while(tmp%i==0) ++sum[top],tmp/=i;//质因数分解 } } if(tmp^1) st[++top]=tmp,sum[top]=1;//加上大质因子 git[1]=1; for(int i=1;i<=top;++i) git[i+1]=git[i]*(sum[i]+1);//git[i]表示,多进制状态下,第i位一个1表明十进制多少 ed=0; for(int i=1;i<=top;++i) ed+=git[i]*sum[i];//ed是最终状态 for(int i=1;i<=n;++i) { if(m%a[i]){vis[i]=1;continue;}//不是M的约数没用 qr=sqrt(a[i]),tot=0; for(int j=2;j<=qr;++j) { if(a[i]%j==0) { c[++tot]=j; while(a[i]%j==0) ++s[i][tot],a[i]/=j;//质因数分解*2 } } if(a[i]^1) c[++tot]=a[i],s[i][tot]=1; int t=1; for(int j=1;j<=top;++j) { while(c[t]<st[j]&&t<tot) ++t; if(c[t]==st[j]) g[i]+=git[j]*s[i][t];//g[i]为a[i]对应的多进制状态数 } } f[0]=1; for(int t,now,flag,i=1;i<=n;++i) { if(vis[i]) continue; for(int j=ed;~j;--j) { flag=0; t=0; for(int k=1;k<=top;++k) { now=(j%git[k+1])/git[k];//now是a[i]对应的g[i]在第i位有多大 if(now+(g[i]%git[k+1])/git[k]>sum[k]){flag=1;break;}//若是第i位当前数字+g[i]的第i位数字大于上界取消 t+=(now+(g[i]%git[k+1])/git[k])*git[k]; } if(flag) continue; f[t]+=f[j]; if(f[t]>=p) f[t]-=p; } } printf("%d\n",f[ed]); } return 0; } } signed main() { return knife_rose::main(); } /* 1 10 10 1 5 1 2 4 5 1 2 1 5 */
猴猴今天要和小伙伴猩猩比赛爬树,为了公平不碰撞,猴猴和猩猩须要在不一样的树上攀爬。因而
它们选了两颗节点数同为n的树,并将两棵树的节点分别以1~n标号(根节点标号为1),但两棵树
的节点链接方式不尽相同。
如今它们决定选择两个标号的点进行比赛。为了方便统计,规定它们比赛中必须都向上爬。(即
选定的赛段节点u→节点v都必须指向叶子方向)请你求出这两棵树上共有多少对节点知足比赛的需
求。
对于30%的数据:n≤1000
对于50%的数据:n≤10000
对于100%的数据:n≤100000,1≤a,b≤n
题意大概是选一对点使得在这两颗树上都知足某个点是另外一个点的祖先
30%:记录每一个点是否是在两棵树上都是本身祖先,枚举点对
50%:???好像没啥办法
100%:其实这个题目就是一个树上逆序对问题,咱们考虑先对第一颗树以dfs序为下标建树状数组,再遍历第二棵树,每次进去的先把本身放进树状数组,而后求一下当前子树范围内点的个数,出来的时候再求一遍,两次结果做差就是知足题目要求的点对(进去的时候不存在而回溯的时候存在说明既是第一颗树的子树也是第二棵树的子树)
#include<bits/stdc++.h> using namespace std; namespace knife_rose{ #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define mid ((l+r)>>1) inline int read() { int x=0;char ch,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') f=0,ch=getchar(); while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } const int N=1e5+10; int n,ret; int head[N],cnt; struct point { int nxt,to; point(){} point(const int &nxt,const int &to):nxt(nxt),to(to){} }a[N<<1]; inline void link(int x,int y) { a[++cnt]=(point){head[x],y};head[x]=cnt; a[++cnt]=(point){head[y],x};head[y]=cnt; } int st[N],ed[N],idx; inline void dfs1(int now,int fa) { st[now]=++idx; for(int i=head[now];i;i=a[i].nxt) { int t=a[i].to; if(t==fa) continue; dfs1(t,now); } ed[now]=idx; } int tr[N]; inline int lowbit(int i) { return i&-i; } inline void update(int x,int k) { for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=k; } inline int query(int y) { int ret=0; for(int i=y;i;i^=lowbit(i)) ret+=tr[i]; return ret; } inline void dfs2(int now,int fa)//树上逆序对 { int ans=query(ed[now])-query(st[now]-1); for(int i=head[now];i;i=a[i].nxt) { int t=a[i].to; if(t==fa) continue; dfs2(t,now); } ret+=query(ed[now])-query(st[now]-1)-ans; update(st[now],1); } signed main() { n=read(); for(int x,y,i=1;i<n;++i) { x=read(),y=read(); link(x,y); } dfs1(1,0); memset(head,0,sizeof(head)); cnt=0; for(int x,y,i=1;i<n;++i) { x=read(),y=read(); link(x,y); } dfs2(1,0); printf("%d\n",ret); return 0; } } signed main() { return knife_rose::main(); }