给出n个点,m条边,求满足一条路径使得m-2条边经过2次,2条边经过1次的方案数.并且题目中给出有自环.
看到题面我以为是个计数DP,可能是计数题做多了吧哈哈.其实仔细朝图的方向想一想就会发现,把每条边double一下,题目的要求就是去掉两条边,然后还能是欧拉路一笔画走完.
欧拉路的性质就是点的度数为偶,或者是其中两点度数为奇数.所以就要考虑拆边怎莫拆.
因为我把路径double了一下,所以现在度数都是偶数,如果随便拆两条边,那么肯定会出现四个单点,所以我拆的两条边要有公共点.在来看自环,很明显自环对奇偶是毫无影响的,所以可以是任意一个自环和一个边,或者是任意两个自环.
以上三种加起来便是方案书.注意要判不联通的情况,而且因为题目是在边上做文章,所以点联不联通是无所谓的,我只需判边,用并查集即可.
code
#include<bits/stdc++.h> #define int long long using namespace std; int n,m,ji,head[300001],in[300001],fa[300001],cnt,sum[300001],ans; struct AYX {int to,next;}bian[600001]; inline int find(int x) { if(x!=fa[x])return fa[x]=find(fa[x]); return x; } inline void add(int u,int v) { bian[++ji].next=head[u]; bian[ji].to=v; head[u]=ji; } signed main() { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;++i)fa[i]=i; for(int i=1;i<=m;++i) { int a,b; scanf("%lld%lld",&a,&b); if(a==b)++cnt,++sum[a],++sum[b]; else {++in[a],++in[b];fa[find(a)]=find(b);} add(a,b);add(b,a); } int ww=0; for(int i=1;i<=n;++i) for(int j=head[i];j;j=bian[j].next) { int v=bian[j].to; if(!ww){ww=find(v);continue;} if(ww!=find(v)) { printf("0\n"); return 0; } } for(int i=1;i<=n;++i)ans+=(in[i]-1)*in[i]/2; ans+=cnt*(cnt-1)/2; ans+=cnt*(m-cnt); printf("%lld\n",ans); }
式子不好搞,额,不是不好推,是不好打...........
maxd 要满足floor(a[i]/d)*d-a[i]<=k;
转化一下得到floor(a[i]/d)<=(k+a[i])/d;
k+a[i]为定值,设为T;则floor(a[i]/d)<=T/d;
明显是数论分块,检查每一个右端点取max就好,因为只有100个数,check时暴力算就行.
复杂度T^(1/2)*n;
code
#include<bits/stdc++.h> #define int long long using namespace std; int n,a[3000001],k,T,ans; inline bool check(int x) { int d=T/x,sum=0; for(int i=1;i<=n;++i) { if(a[i]%x==0)sum+=a[i]/x; else sum+=a[i]/x+1; } return sum<=d; } inline void work() { for(int l=1,r;l<=T;l=r+1) { r=T/(T/l); if(check(r))ans=max(ans,r); } printf("%lld\n",ans); } signed main() { scanf("%lld%lld",&n,&k); for(int i=1;i<=n;++i)scanf("%lld",&a[i]),T+=a[i]; T+=k; work(); }
这个计数dp不好搞,这是真不好搞.
f[i][j]表示第i个,有j条点不重复的路径.
设num=f[i-1][l]*f[i-1][r];
f[i][l+r]+=num;这是对这棵树神魔也不做.
f[i][l+r+1]+=num;这是将跟节点作为一条新路径.
f[i][l+r]+=num(l+r)2;这是将根连到左右子树的某个路径上.
f[i][l+r-1]+=num* l* r *2;这是将根与左右各一条相连.
f[i][l+r-1]+=num(l(l-1)+r*(r-1));这是根与同一子树中两条路径相连.
因为最终对ans有贡献的只有k个状态,所以第二维只有k.
code
#include<bits/stdc++.h> #define re register using namespace std; int k,mod; long long f[3001][3001]; signed main() { scanf("%d%d",&k,&mod); f[1][0]=f[1][1]=1; for(re int i=2;i<=k;++i) for(re int j=0;j<=k;++j) for(re int r=0;r<=j;++r) { int l=j-r; long long sum=f[i-1][l]*f[i-1][r]%mod; f[i][l+r]=(f[i][l+r]+sum)%mod; f[i][l+r+1]=(f[i][l+r+1]+sum)%mod; f[i][l+r]=(f[i][l+r]+sum*2*(l+r))%mod; f[i][l+r-1]=(f[i][l+r-1]+2*sum*l*r)%mod; f[i][l+r-1]=(f[i][l+r-1]+sum*(l*(l-1)+r*(r-1)))%mod; } printf("%lld\n",f[k][1]%mod); }
数据超水,暴力都能撵过去,可惜我没mod,100-->0..............
正解也够暴力的,就是预处理每个dep的1-50次方,和其前缀和.询问时求lca,O(1)搞出ans;
code就借WTZ一用,也算有咱一半产权吧.
#include<bits/stdc++.h> #define mod 998244353 #define int long long using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } inline void write(int x){ if(x<0) x=-x,putchar('-'); if(x>10) write(x/10); putchar(x%10+'0'); } int n,m,ans; int siz[300010],fa[300010],son[300010],top[300010],dep[300010],mxd=0; int depk[300010][51],sum[300010][51]; int head[300010],ver[600010],to[600010],tot; inline void add(int x,int y){ ver[++tot]=y; to[tot]=head[x]; head[x]=tot; } inline void dfs1(int x,int fath,int depth){ int maxson=-1; fa[x]=fath,dep[x]=depth,siz[x]=1;mxd=max(mxd,depth); for(int i=head[x];i;i=to[i]){ int y=ver[i]; if(y==fath) continue; dfs1(y,x,depth+1); siz[x]+=siz[y]; if(siz[y]>maxson) son[x]=y,maxson=siz[y]; } } inline void dfs2(int x,int topf){ top[x]=topf; if(!son[x]) return; dfs2(son[x],topf); for(int i=head[x];i;i=to[i]){ int y=ver[i]; if(y==fa[x]||y==son[x]) continue; dfs2(y,y); } } inline int LCA(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); return x; } signed main(){ n=read(); for(int i=1,x,y;i<n;i++){ x=read(),y=read(); add(x,y),add(y,x); } dfs1(1,0,0);dfs2(1,1); for(int i=1;i<=mxd;i++){ depk[i][1]=i; for(int j=2;j<=50;j++) depk[i][j]=depk[i][j-1]*i%mod; } for(int i=1;i<=mxd;i++) for(int j=1;j<=50;j++) sum[i][j]=(sum[i-1][j]+depk[i][j])%mod; m=read(); for(int i=1,x,y,k,lca;i<=m;i++){ x=read(),y=read(),k=read(); lca=LCA(x,y); ans=0; ans=(sum[dep[x]][k]-sum[dep[lca]][k]+mod)%mod+(sum[dep[y]][k]-sum[dep[fa[lca]]][k]+mod)%mod; printf("%lld\n",ans%mod); } return 0; }