17.10.28B组总结

17.10.28B组总结

T1

一道数论题,某ZYS大佬推了两个多小时,考场切掉,然而我并不想花时间在50分上(大众分30~50),正解那一波式子真的烦,大致如下:
我们设f[i]表示i层k叉数的数量,则

f[i]=ki1k1

那么我们发现
ans=i=0n1(f[ni+1]2kf[ni]2)iki

代入得
ans=i=0n1((kni+11k1)2k(kni1k1)2)iki

化简一下就得到
ans=n1i=0ikiik2ni+1k1

算了,不说这么多了,总之就是:
k2nk(2n1)kn(k1)(k1)3

记得用逆元。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const ll mo=998244353;
ll n,k,ans,t;
ll qsm(ll x,ll y)
{
    ll z=1;
    while (y)
    {
         if (y&1)
            z=z*x%mo;
        x=x*x%mo,y/=2;
    }
    return z;
}
int main( )
{
    scanf("%lld%lld",&n,&k);
    ans=((qsm(k,2*n)-k-(2*n-1)*qsm(k,n)%mo*(k-1)%mo+mo)%mo+mo)%mo;
    t=qsm(k-1,3);
    ans=ans*qsm(t,mo-2)%mo;
    printf("%lld\n",ans);
}

T2

作为一道暴力都轻松a的题,不必多说。
看到数据b串仅有20位,于是乎很自然的想到了暴力,仅仅只有 O(2mn) 而已,但是看上去貌似过不了,纪中数据水呀。

#include <cstdio>
#include <iostream>
#include <cstring>
#define fo(i,a,b) for (int i=a;i<=b;i++)
using namespace std;
char a[100010],b[30],st[30];
int n,m,len,ans;
bool bz[100010];
inline void dfs(int x)
{
    if (x>m)
    {
        len=0;
        fo(i,1,m) 
            if (bz[i]) 
                st[++len]=b[i];
        fo(i,1,len/2) 
            if (st[i]!=st[len-i+1]) 
                return;
        int i=1,j=1;
        fo(i,1,n)
        {
            if (a[i]==st[j]) 
                j++;
            if (j>len)
                break;
        }
        if (j<=len) 
            return;
        ans=max(ans,len); 
        return;
    }
    bz[x]=true,dfs(x+1);
    bz[x]=false,dfs(x+1);
}
int main()
{
    scanf("%s",a+1);
    scanf("%s",b+1);
    n=strlen(a+1);
    m=strlen(b+1);
    dfs(1);
    printf("%d\n",ans);
}

T3

又是随机,考试直接弃疗(连暴力都不会打)。
然而事实告诉我们,不要畏惧他,它仅仅只是一个树形DP而已。
我们设 f[i,j] 表示现在在节点i走到节点j且满足i和j有边直接相连的期望长度。
可以得到

f[i,j]=1d[i]+kik!=j1+f[k,i]+f[i,j]d[i]

(d[i]表示i的度数)
化简得
f[i,j]=d[i]+kik!=jf[k,i]

接着设 1 为根,跑一遍 DFS,自下而上计算出所有的 f[i,fa[i]]
机智的我们又可以观察到
f[i,fa[i]]=jid[j]=size[i]21

那么很显然
f[i,fa[i]]+f[fa[i],i]=n22

于是就可以求出 f[fa[i],i] 了。
那么我们就可以设a[x]表示x到x的子树内的最大期望距离,b[x]表示x的子树内到x的最大期望距离,然后按照顺序把x的子树到x的距离排好,然后维护一个前缀max和后缀max就好了。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int n,cnt,ans,last[N],d[N],f[N],g[N],a[N],b[N],c[N],mx1[N],mx2[N];
struct edge{int to,next;}e[N*2];
void insert2(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
    e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}
void dfs(int x,int fa)
{
    int i,s=0,s1=0;
    mx1[0]=mx2[s+1]=0;
    f[x]=d[x];
    for (i=last[x];i;i=e[i].next)
    {
        if(e[i].to==fa)continue;
        dfs(e[i].to,x);
        f[x]+=f[e[i].to];
        a[x]=max(a[x],a[e[i].to]+g[e[i].to]);
        b[x]=max(b[x],b[e[i].to]+f[e[i].to]);
    }
    for (i=last[x];i;i=e[i].next)
        c[++s]=a[e[i].to]+g[e[i].to];
    for (i=1;i<=s;i++)
    {
        mx1[i]=max(mx1[i-1],c[i]);
        mx2[s-i+1]=max(mx2[s-i+2],c[s-i+1]);
    }
    for (i=last[x];i;i=e[i].next)
    {
        if (e[i].to==fa) continue;
        ans=max(ans,b[e[i].to]+f[e[i].to]+max(mx1[(++s1)-1],mx2[s1+1]));
    }
    g[x]=n*2-f[x]-2;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        insert2(x,y);
        d[x]++;d[y]++;
    }
    dfs(1,0);
    printf("%d.00000",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值