绵阳东辰国际test201910.21

亡梦爱人 提交于 2019-12-01 20:23:10

爆零警告,昨天晚上睡得晚,考试的时候困死我了

分析:

哈密尔顿环:每个点只经过一次的路线,有哈密尔顿环的图叫哈密尔顿图

先考虑只是一条链

很容易想到隔一个跳一次,这样无论链有多长一定是从A出发,B回来

所以直接拓展到树上即可:

如 果当前节点深度是奇数,那么我们在DFS前输出这个点,

否则在DFS完所有孩子之 后再输出这个点。

part code:

il void dfs(int u,int fa){       dp[u]=dp[fa]+1;       if(dp[u]&1){printf("%d\n",u);}       for(ri i=head[u];i;i=edg[i].next){       int to=edg[i].to;       if(to==fa)continue;       dfs(to,u);       }       if(!(dp[u]&1)){printf("%d\n",u);} }

什么跳两次的滚出

总结:有很多的dfs题代码很简单,却很容易陷阱去,导致思路开花,应该往简单的方向想

不禁想到一句诗:众里寻他千百度,那人却在灯火阑珊处

分析:

首先用kmp或者哈希对每个 Ti,求出它在 S 中的匹配位置

那么这些位置 中至少得要删掉一个

考虑如果两个区间的R相等时,这时就只用管L最大的

证明

为什么因为先满足L较大的,其他的同R的肯定都满足了

而先满足L较小的,L较大的不一定满足,所以这样一定是最优的

于是对于每个 i,我们可以求出一个 Li

如果没有的直接从前面dp转移过来就可以

然后很明显就要dp

设dp[i]前i个位置都满足,且最后一个删的是i的最小值

Li是单调递增的

所以维护单调递增队列dp

code by CHiTongZi

#include <bits/stdc++.h> using namespace std; const int N = 2e5 + 5; char S[N], T[N]; int n, m, a[N], d[N]; inline void calc () {     static int nxt[N];     int cur = 0, len = strlen (T + 1);     for (int i = 2; i <= len; ++i)     {         while (cur && T[cur + 1] != T[i]) cur = nxt[cur];         nxt[i] = cur + (T[cur + 1] == T[i]);         cur += T[cur + 1] == T[i];     }      cur = 0;     for (int i = 1; i <= n; ++i)     {         while (cur && T[cur + 1] != S[i]) cur = nxt[cur];         if (T[cur + 1] == S[i]) cur++;         if (cur == len) d[i] = max (d[i], i - len + 1), cur = nxt[cur];     } } int q[N], p[N], dp[N], tail = 1, head = 1; inline void insert (int vv, int k) {     while (tail >= head && q[tail] >= k) tail--;     q[++tail] = k;     p[tail] = vv; } inline int query (int lp) {     while (tail >= head && p[head] < lp) head++;     return q[head]; } int main () {     memset (d, -1, sizeof d);     scanf ("%d%d", &n, &m);     scanf ("%s", S + 1);     for (int i = 1; i <= n; ++i)scanf ("%d", &a[i]);     for (int i = 1; i <= m; ++i)scanf ("%s", T + 1), calc();     int rpoint = -1;     for (int i = 1; i <= n ; ++i)     {         if (rpoint >= d[i])d[i] = -1;         rpoint = max (rpoint, d[i]);     }     for (int i = 1; i <= n; ++i)     {         insert (i, a[i] + dp[i - 1]);         if (d[i] == -1) dp[i] = dp[i - 1];         else dp[i] = query (d[i]);     }     printf ("%d\n", dp[n]);     return 0; }

分析:
问题转化:u 的子树中选 k 个点使它们两两 LCA 是 u 的方案数,对 v 也求同样的东西,

再把两者相乘就是最后的答案了

有可能u,v 存在祖孙关系,

不妨设 u 是 v 的祖先,那么 u 的子树就要改为以 v 的 方向作为根方向前提下的子树

然后就乱搞就行了

code:

#include<bits/stdc++.h> #define del(a,i) memset(a,i,sizeof(a)) #define ll long long #define inl inline #define il inl void #define it inl int #define ill inl ll #define re register #define ri re int #define rl re ll #define mid ((l+r)>>1) #define lowbit(x) (x&(-x)) #define INF 0x3f3f3f3f using namespace std; template<class T>il read(T &x){     int f=1;char k=getchar();x=0;     for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;     for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';     x*=f; } template<class T>il _print(T x){     if(x/10) _print(x/10);     putchar(x%10+'0'); } template<class T>il print(T x){     if(x<0) putchar('-'),x=-x;     _print(x); } ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;} it qpow(int x,int m,int mod){     int res=1,bas=x%mod;     while(m){         if(m&1) res=(1ll*res*bas)%mod;         bas=(1ll*bas*bas)%mod,m>>=1;     }     return res%mod; } const int MAXN = 1e5+5,mod = 998244353; int n,m,L,u,v,k,head[MAXN],num_edge,dp[MAXN][505]; struct Edge{     int next,to;     Edge(){}     Edge(int next,int to):next(next),to(to){} }edge[MAXN<<1]; il add_edge(int u,int v){     edge[++num_edge]=Edge(head[u],v),head[u]=num_edge;     edge[++num_edge]=Edge(head[v],u),head[v]=num_edge; } it add(int x,int y){return x+y>=mod?x+y-mod:x+y;} it mul(int x,int y){return 1ll*x*y%mod;} int f[MAXN][18],dep[MAXN],sz[MAXN],deg[MAXN]; il DFS(int u,int fa){     sz[u]=1,f[u][0]=fa,dep[u]=dep[fa]+1;     for(ri i=1;i<=17;++i) f[u][i]=f[f[u][i-1]][i-1];     for(ri i=head[u];i;i=edge[i].next){         if(edge[i].to==fa) continue;         DFS(edge[i].to,u);         sz[u]+=sz[edge[i].to];     } } it LCA(int u,int v){     if(dep[u]<dep[v]) swap(u,v);     for(ri i=17;i>=0;--i) if(dep[f[u][i]]>=dep[v]) u=f[u][i];     if(u==v) return u;     for(ri i=17;i>=0;--i)         if(f[u][i]!=f[v][i])             u=f[u][i],v=f[v][i];     return f[u][0]; } it jump(int u,int lca){//找到u到lca这条路径上除了lca外深度最小的点     for(ri i=17;i>=0;--i)         if(dep[f[u][i]]>dep[lca])             u=f[u][i];     return u; } il calc(int u){//dp[u][i]表示在u的子树中选择其中i颗上的点的方案数。     dp[u][0]=1;     for(ri i=head[u];i;i=edge[i].next){         if(edge[i].to==f[u][0]) continue;         for(ri j=deg[u];j;--j)             dp[u][j]=add(dp[u][j],mul(dp[u][j-1],sz[edge[i].to]));     }     for(ri i=deg[u];i;--i)         dp[u][i]=add(dp[u][i],mul(dp[u][i-1],n-sz[u])); } int fac[MAXN],ifac[MAXN],inv[MAXN]; il init(){     for(ri i=1;i<=n;++i) calc(i);     fac[0]=ifac[0]=inv[1]=1;     for(ri i=1;i<=L;++i) fac[i]=mul(fac[i-1],i);     ifac[L]=qpow(fac[L],mod-2,mod);     for(ri i=L-1;i;--i) ifac[i]=mul(ifac[i+1],i+1);     for(ri i=2;i<=n;++i) inv[i]=mul(mod-mod/i,inv[mod%i]); } it C(int n,int m){return mul(fac[n],mul(ifac[n-m],ifac[m]));} int ans[MAXN],tmp[MAXN]; it solve(int u,int k,int t){     for(ri i=1;i<=deg[u];++i) ans[i]=0;//ans表示在背包中去掉大小为t的部分后的答案     for(ri i=1;i<=deg[u];++i) tmp[i]=dp[u][i]; //tmp表示原来的答案     //由于背包问题具有交换性(加入背包顺序可以改变),所以我们可以看做t是最后被加入背包的     //因为我们有tmp[i]=ans[i]+ans[i-1]*sz,且在加入最后一个之前dp[deg[u]]=0,所以我们可以倒着推出ans[i]     //即ans[i-1]=(tmp[i]-ans[i])/sz     for(ri i=deg[u];i;--i){         ans[i-1]=mul(tmp[i],inv[t]);         tmp[i]=0,tmp[i-1]=add(tmp[i-1],mod-ans[i-1]);     }     ri res=0;     for(ri i=0;i<=min(deg[u],k);++i) res=add(res,mul(mul(fac[i],ans[i]),C(k,i)));     return res; } int main(){ //  freopen(".in","r",stdin); //  freopen(".out","w",stdout);     read(n),read(m),read(L);     for(ri i=1;i<n;++i) read(u),read(v),add_edge(u,v),++deg[u],++deg[v];     DFS(1,0);     init();     for(ri i=1;i<=m;++i){         read(u),read(v),read(k);         if(dep[u]<dep[v]) swap(u,v);         ri lca=LCA(u,v);         if(lca!=v) print(mul(solve(u,k,n-sz[u]),solve(v,k,n-sz[v]))),puts("");         else{             ri t=jump(u,lca);             print(mul(solve(u,k,n-sz[u]),solve(v,k,sz[t]))),puts("");         }     }     return 0; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!