20170424模拟赛

今天没有菜醒所以就没爆零了?

进考场很快的看完了题后吐槽liaoliao怎么把剧情改了(虽然我挺兹瓷的),四道题好像都没什么初步的想法,于是开始想T1
第一题的数据范围好像还是挺兹瓷一些比较玄妙的网络流的毕竟这东西我也不知道复杂度,想了一会感觉不会呀..我不会..恩那一定不是…然后把自己带入了兔子的角色…唉这..是个贪心吧…想了想好像很有道理,就先看第二题了
第二题对着部分分yy了一个*1000的做法…,不会了,先跳吧
第三题一开始想分2种做DP,总感觉不太对,很快想了一个数据把这种做法叉掉了,那..枚举拿部分分?跳T4
看完…没看懂,liaoliao解释了样例后果断这题不可做水个部分分算了

看时间好像不多的样子,就开始码码码
码完感觉时间好像还挺多的…
想了一会T2,感觉做过很像的题,推一下,推到一个二项式就不会了,并不会处理下界的情况,想了一会还是稳一点水部分分比较靠谱

四题代码查了一遍错后又看了一遍题…还剩15min,发现我T1看漏了,想了下感觉差别不会太大,改改改…
然后感觉差不多就交了
然后T1挂了
听完题解好气呀,少写了一个堆,后来改的时候没想到(不擅长各类贪心)

题解:
T1:
第一天肯定在保证选到k只兔子的情况下尽量选那些能连续采集的天数比较长的
维护一个大根堆,从第二天开始,堆里存这天能采集的兔子,权值为他们从这天连续采集到哪一天后不能采集,
再维护一个小根堆存前一天采集的兔子,再保证了选到k只兔子,这天选的兔子不超L的情况下拿大根堆里的兔子替换小根堆里的兔子到不能替换
T2:
可以发现f[n]用到的状态一定是f[n-a-b×pi]的形式,找出下界的 n-a-b×pi, Caa+b 就是他对f[n]的贡献
T3:
很常规的期望呢
处理出不砍边,每个点走下去经过边数的期望,那么砍掉一条边,他影响的是出边节点的f值,算出f变换多少,乘上1走到出边节点的概率就是砍掉这条边的贡献
T4:51nod1628
liaoliao的做法似乎和正解不一样,然后我们就都不一样了呃(表示我这题nod上倒1卡过去的233)
倍增+矩乘
我们可以将链分成两条直链,只要链兹瓷合并,就可以求值了

我们维护这棵树,每个节点向上走2^i个节点,路径上的点组成的链的信息
对于每条这样的链,我们维护:

这条链上接的所有树的所有节点(除去这个链的底端节点的树),到这条链的顶端经过路径和这条链的交点数对应的fib的和(以fib转移矩阵的和的形式保存,矩乘满足分配律),
这些节点到这条链的底端节点经过路径和这条链(不算底端节点)的交点数对应的fib的和(以fib转移矩阵和的形式保存),
这些节点之间两两配对的路径和这条链(仍然不考虑底端,事实上因为这些节点中无底端的树的节点,他们配对的路径也不会和底端有交点)的交点对应的fib的ans的和,
以f[x][i],uf[x][i],ans[x][i]保存(前两个存的是矩阵,ans存的是数,i表示链是以x为低端节点,向上走2^i个节点)

考虑两条链的合并,两条长度为2^i的链(a->b,b->c的两条链)合并在一起,设a向根走2^i个节点到b,b走2^i个节点到c,那么新的链,长为2^(i+1),他的状态的转移为

f[a][i+1]=f[a][i]*st^(2^i)+f[b][i],st为fib转移矩阵,新的f为原来b->c上那些点到c的矩阵和,加上a->b上那些点走到b再到c的矩阵和,因为a->b的那些点到c一定要经过b->c这条链,与链的交点数都增加了2^i个,所以要乘转移矩阵的2^i次方
uf[a][i+1]=f[a][i]+f[b][i]*st^(2^i),uf同理
ans[a][i+1]=ans[a][i]+ans[b][i]+f0*f[a][i]*uf[b][i],f0为fib初始矩阵,即新的ans是原来两条链上各自两两匹配的ans,加上a->b上接的树的那些点和b->c上接的树的那些点之间匹配

对于询问,直链就这样合并,否则分成两条直链和LCA三部分合并,与预处理的合并类似,要处理子树外的那些点,细节有点多注意一下
我特判了链上只有一个点的情况
code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void swap(int &x,int &y){x^=y;y^=x;x^=y;}
const ll Mod = 1000000009;
const int maxn = 100005;
const int maxd = 18;

int n,m;
struct matrix
{
    int a[2][2];
    matrix(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;}
    friend inline matrix operator +(matrix &x,matrix &y)
    {
        matrix ret;
        for(int i=0;i<2;i++) for(int j=0;j<2;j++)
            ret.a[i][j]=((ll)x.a[i][j]+y.a[i][j])%Mod;
        return ret;
    }
    friend inline matrix operator -(matrix &x,matrix &y)
    {
        matrix ret;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
            {
                ret.a[i][j]=x.a[i][j]-y.a[i][j];
                if(ret.a[i][j]<0) ret.a[i][j]+=Mod;
            }
        return ret;
    }
    friend inline  matrix operator *(matrix &x,matrix &y)
    {
        matrix ret;
        for(int i=0;i<2;i++)
            for(int k=0;k<2;k++)
                for(int j=0;j<2;j++)
                    (ret.a[i][j]+=(ll)x.a[i][k]*y.a[k][j]%Mod)%=Mod;
        return ret;
    }
    friend inline matrix operator ^(matrix &x,int &y)
    {
        matrix ret; ll ty=y;
        for(int i=0;i<2;i++) for(int j=0;j<2;j++)
            ret.a[i][j]=(ll)x.a[i][j]*ty%Mod;
        return ret;
    }
}f0,st,f[maxn][maxd],uf[maxn][maxd],pw[maxd];

struct edge
{
    int y,nex;
    edge(){}
    edge(const int _y,const int _nex){y=_y;nex=_nex;}
}a[maxn<<1]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=edge(y,fir[x]);fir[x]=len;}

int siz[maxn],dep[maxn],fa[maxn][maxd];
void dfs(const int x)
{
    siz[x]=1;
    for(int i=1;i<maxd&&dep[x]>(1<<i);i++) 
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int k=fir[x];k;k=a[k].nex)if(a[k].y!=fa[x][0])
    {
        dep[a[k].y]=dep[x]+1; fa[a[k].y][0]=x;
        dfs(a[k].y); siz[x]+=siz[a[k].y];
    }
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=maxd-1;i>=0;i--) if(dep[x]-dep[y]>=(1<<i)) x=fa[x][i];
    if(x==y) return x;
    for(int i=maxd-1;i>=0;i--)
        if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
ll ans[maxn][maxd];
ll count(int N) { return (ll)(N-1)*N/2ll; }
void pre()
{
    for(int i=2;i<=n;i++)
    {
        const int y=fa[i][0];
        int num=siz[y]-siz[i];
        ans[i][0]=count(num);
        for(int k=fir[y];k;k=a[k].nex) if(a[k].y!=fa[y][0]&&a[k].y!=i)
            ans[i][0]-=count(siz[a[k].y]);
        ans[i][0]%=Mod;

        int tt=(siz[y]-siz[i]);
        uf[i][0]=f[i][0]=st^tt;
    }
    matrix nw=st; for(int i=0;i<maxd;i++,nw=nw*nw) pw[i]=nw;
    for(int d=1;d<maxd;d++)
    {
        for(int i=2;i<=n;i++) if(dep[i]>(1<<d))
        {
            matrix tt=f[i][d-1]*uf[fa[i][d-1]][d-1];
            ans[i][d]=(ans[i][d-1]+ans[fa[i][d-1]][d-1]+(f0*tt).a[0][0])%Mod;

            tt=f[i][d-1]*pw[d-1];
            f[i][d]=tt+f[fa[i][d-1]][d-1];

            tt=uf[fa[i][d-1]][d-1]*pw[d-1];
            uf[i][d]=uf[i][d-1]+tt;
        }
    }
}


int main()
{

    f0.a[0][1]=1ll;
    st.a[0][0]=1; st.a[0][1]=1; st.a[1][0]=1;

    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y; scanf("%d%d",&x,&y);
        ins(x,y); ins(y,x);
    }
    dep[1]=1; dfs(1);

    pre();
    scanf("%d",&m);
    while(m--)
    {
        int x,y; scanf("%d%d",&x,&y);
        if(x==y)
        {
            ll re=count(n);
            for(int k=fir[x];k;k=a[k].nex)
                re-=count(a[k].y==fa[x][0]?n-siz[x]:siz[a[k].y]);
            re%=Mod;
            printf("%lld\n",re);
            continue;
        }
        if(dep[x]>dep[y]) swap(x,y);
        int L=LCA(y,x);
        if(L==x)
        {
            ll re=count(siz[y]);
            for(int k=fir[y];k;k=a[k].nex) if(a[k].y!=fa[y][0])
                re-=count(siz[a[k].y]);
            re%=Mod;

            matrix fx=st^siz[y];

            for(int i=maxd-1;i>=0;i--) if(dep[y]-dep[x]>(1<<i))
            {
                matrix tt=fx*uf[y][i];
                (re+=ans[y][i]+(f0*tt).a[0][0])%=Mod;
                tt=fx*pw[i];
                fx=tt+f[y][i];
                y=fa[y][i];
            }
            int num=n-siz[y]-1;
            re+=count(num);
            for(int k=fir[x];k;k=a[k].nex) if(a[k].y!=y) 
                re-=count(a[k].y==fa[x][0]?n-siz[x]:siz[a[k].y]);
            re%=Mod;

            fx=fx*st; (re+=(f0*fx).a[0][0])%=Mod;
            fx=fx+st; matrix tt=fx^num;
            (re+=(f0*tt).a[0][0])%=Mod;

            if(re<0) re+=Mod;
            printf("%lld\n",re);
        }
        else
        {
            ll re=count(siz[x])+count(siz[y]);
            for(int k=fir[x];k;k=a[k].nex) if(a[k].y!=fa[x][0])
                re-=count(siz[a[k].y]);
            for(int k=fir[y];k;k=a[k].nex) if(a[k].y!=fa[y][0])
                re-=count(siz[a[k].y]);
            re%=Mod;

            matrix fx=st^siz[x];
            for(int i=maxd-1;i>=0;i--) if(dep[x]-dep[L]>(1<<i))
            {
                matrix tt=fx*uf[x][i];
                (re+=ans[x][i]+(f0*tt).a[0][0])%=Mod;
                tt=fx*pw[i];
                fx=tt+f[x][i];
                x=fa[x][i];
            }

            matrix fy=st^siz[y];
            for(int i=maxd-1;i>=0;i--) if(dep[y]-dep[L]>(1<<i))
            {
                matrix tt=fy*uf[y][i];
                (re+=ans[y][i]+(f0*tt).a[0][0])%=Mod;
                tt=fy*pw[i];
                fy=tt+f[y][i];
                y=fa[y][i];
            }

            matrix tt;
            tt=fx*st;
            (re+=(f0*tt).a[0][0])%=Mod;
            fx=tt+st;
            tt=fx*fy;
            (re+=(f0*tt).a[0][0])%=Mod;
            fy=fy*st;

            matrix fL=fx+fy;
            int num=n-siz[x]-siz[y]-1;
            tt=fL^num;
            (re+=(f0*tt).a[0][0])%=Mod;

            re+=count(num);
            for(int k=fir[L];k;k=a[k].nex) if(a[k].y!=x&&a[k].y!=y)
                re-=count(a[k].y==fa[L][0]?n-siz[L]:siz[a[k].y]);
            re%=Mod;
            if(re<0) re+=Mod;
            printf("%lld\n",re);
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值