QDC DAY1

  暴毙了,比较自闭的心理,有点崩溃..

LINK:幸福 一道曾经的我肯定能写出来的 但是我心态崩了 所以没有推出来。

当然 还是 我比较垃圾 但同时也不垃圾 。。。

求 $T_n =\displaystyle \sum_{i=0}^{n}F_n$ 其中 $Fn=\displaystyle \sum_{i=0}^{n}f_i \times f_{n-i}$

其中$f$是斐波那契数列 $f_0=1,f_1=1$... 求 $F_n$ 其中n<=1e18

 一个比较显然的思路是把Tn 写出来不断化简 最后发现是一个前缀和的形式 然后发现可以O(n)计算了。

这样只有70分的垃圾成绩。

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000010
#define ll long long
#define mp(x,y) make_pair(x,y)
#define un unsigned
#define db double
#define EPS 1e-5
#define mod 998244353
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
    ll x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const ll MAXN=1000010;
ll n;
ll ans,sum;
ll f[MAXN];
signed main()
{
    //freopen("1.in","r",stdin);
    n=read();
    f[0]=1;f[1]=1;
    for(ll i=2;i<=n;++i)f[i]=(f[i-1]+f[i-2])%mod;
    if(n<=20000)
    {
        for(ll i=0;i<=n;++i)
        {
            for(ll j=0;j<=i;++j)
                ans=(ans+f[j]*f[i-j])%mod;
        }
        printf("%lld\n",ans);
        return 0;
    }
    if(n<=1000000)
    {
        for(int i=0;i<=n;++i)sum=(sum+f[i])%mod;
        for(int i=0;i<=n;++i)
        {
            sum=((sum-f[n-i+1])+mod)%mod;
            ans=(ans+f[i]*sum%mod)%mod;
        }
        printf("%lld\n",ans);
        return 0;
    }
    //考虑 100分 容斥还没有想好 自闭
    printf("%lld\n",ans);
    return 0;
}
View Code

继续思考如何优化 发现这个其实是倒三角求和 扩大两倍是不正确的 所以我当时 算2h然后弃疗了。思考方向不是太对。

观察一下$F_n$这个式子。 简单的 化简成 $F_n=\sum_{i=0}^{n-2f_i \times f_{n-i}+f_{n-1}f_1+f_n+f_0$

比较显然的是 这个东西显然可以 化简为 $F_n=F_{n-1}+F_{n-2}+f_n$;

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define INF 1000000010
#define mod 998244353
typedef long long ll;
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
    ll x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const ll MAXN=6;
ll n,m=5;
struct wy
{
    ll f[MAXN];
    ll b[MAXN][MAXN];
    wy(){memset(f,0,sizeof(f));memset(b,0,sizeof(b));}
    friend wy operator *(wy A,wy B)
    {
        wy tmp;
        for(ll i=1;i<=m;++i)
            for(ll j=1;j<=m;++j)
                for(ll k=1;k<=m;++k)
                    tmp.b[i][j]=(tmp.b[i][j]+A.b[i][k]*B.b[k][j])%mod;
        for(int i=1;i<=m;++i)tmp.f[i]=A.f[i];
        return tmp;
    }
    friend wy operator -(wy A,wy B)
    {
        wy tmp;
        for(ll i=1;i<=m;++i)
            for(ll j=1;j<=m;++j)
                tmp.f[i]=(tmp.f[i]+A.f[j]*B.b[j][i])%mod;
        for(int i=1;i<=m;++i)
            for(int j=1;j<=m;++j)tmp.b[i][j]=A.b[i][j];
        return tmp;
    }
    friend wy operator ^(wy A,ll p)
    {
        while(p)
        {
            if(p&1)A=A-A;
            A=A*A;
            p=p>>1;
        }
        return A;
    }
}C;
signed main()
{
    //freopen("1.in","r",stdin);
    n=read();
    C.b[1][2]=1;C.b[2][1]=1;C.b[2][2]=1;C.b[2][4]=1;
    C.b[3][4]=1;C.b[4][3]=1;C.b[4][4]=1;C.b[3][5]=1;
    C.b[4][5]=1;C.b[5][5]=1;C.b[2][5]=1;
    C.f[1]=1;C.f[2]=2;C.f[3]=1;C.f[4]=2;C.f[5]=3;
    C=C^(n-1);
    printf("%lld\n",C.f[m]);
    return 0;
}
View Code

 所以 就有了 矩阵乘法的优化 以后要敏感一点 或者从不同的方向推一下。

LINK:树链刨分简单的树形dp但需要一些小细节。 当时 可能有一点点慌 所以 题目没怎么看的懂。

想想当时还是比较蠢的。但是过后做法还是很容易就看出来的了。

首先是代价的问题 这个进行 简单的树上差分即可解决。考虑 求答案 不知道哪个点是根。

很好 那么 直接 就 直接一点 以 1 为根 那么答案 我们显然可以贪心的统计出来。

考虑换根。这里值得注意的是 我们是将边权转点权了 看起来很不形象的样子其实可以直接放到边权上 不过那也应该是点权的样子存在着。

直接换根吧 然后有一个细节 其实主要过程是 x 到 y的换根 这里维护一个最大值和次大值就是为了防止y是x的最大值什么的。

还有一点是 换过根之后的话 x就光荣的成为了y的儿子了 在y 继续向下换根的过程中 y的最大值和 次大值应该要被x所更新。(重点 不要像我这个sb一样没注意到)

当然这个swap是必要的qwq 。。因为 swap x y 是要把x变成y的儿子 再swap回来是为了保证原本的关系 因为x其他儿子还需要转移。

//#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<stack>
#include<algorithm>
#include<vector>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<map>
#define max(x,y) ((x)>(y)?(x):(y))
#define INF 1000000010
#define ll long long
#define mp(x,y) make_pair(x,y)
#define un unsigned
#define db double
#define EPS 1e-5
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
    ll x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const ll MAXN=1000010;
ll n,len,m,sum,cnt;
ll lin[MAXN],nex[MAXN<<1],ver[MAXN<<1];
ll sz[MAXN],vis[MAXN],f[MAXN],s[MAXN],son[MAXN],sx[MAXN];
struct wy
{
    ll x,y,lca;
}t[MAXN];
vector<ll>g[MAXN],id[MAXN];
inline void add(ll x,ll y)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
}
inline ll getfather(ll x){return x==f[x]?x:f[x]=getfather(f[x]);}
inline void dfs(ll x)
{
    vis[x]=1;f[x]=x;
    for(ll i=lin[x];i;i=nex[i])
    {
        ll tn=ver[i];
        if(vis[tn])continue;
        dfs(tn);
        f[tn]=x;
    }
    for(unsigned ll i=0;i<g[x].size();++i)
    {
        ll tn=g[x][i];
        ll ID=id[x][i];
        if(vis[tn])t[ID].lca=getfather(tn);
    }
}
inline void dfs(ll x,ll father)
{
    f[x]=0;
    for(ll i=lin[x];i;i=nex[i])
    {
        ll tn=ver[i];
        if(tn==father)continue;
        dfs(tn,x);
        sz[x]+=sz[tn];
        if(sz[son[x]]<sz[tn])son[x]=tn;
        f[x]+=f[tn];
    }
    for(ll i=lin[x];i;i=nex[i])
    {
        ll tn=ver[i];
        if(tn==father)continue;
        if(son[x]==tn)continue;
        if(sz[sx[x]]<sz[tn])sx[x]=tn;
    }
    f[x]+=sz[son[x]];sum+=sz[x];
}
inline void dp(ll x,ll father)
{
    for(ll i=lin[x];i;i=nex[i])
    {
        ll tn=ver[i];
        if(tn==father)continue;
        s[tn]=f[tn]-sz[son[tn]]+s[x]-f[tn];
        if(son[x]==tn)s[tn]=s[tn]-sz[tn]+sz[sx[x]];
        swap(sz[x],sz[tn]);
        if(sz[x]>sz[son[tn]])
        {
            sx[tn]=son[tn];
            son[tn]=x;
        }
        else if(sz[x]>sz[sx[tn]])sx[tn]=x;
        s[tn]+=sz[son[tn]];
        dp(tn,x);
        swap(sz[x],sz[tn]);
    }
}
signed main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    n=read();m=read();
    for(ll i=1;i<n;++i)
    {
        ll x,y;
        x=read();y=read();
        add(x,y);add(y,x);
    }
    for(ll i=1;i<=m;++i)
    {
        ll x,y;
        x=read();y=read();
        t[i]=(wy){x,y};
        if(x==y){t[i].lca=x;continue;}
        g[x].push_back(y);
        g[y].push_back(x);
        id[x].push_back(i);
        id[y].push_back(i);
    }
    dfs(1);
    for(ll i=1;i<=m;++i)
    {
        ++sz[t[i].x];++sz[t[i].y];
        --sz[t[i].lca];--sz[t[i].lca];
    }
    dfs(1,0);s[1]=f[1];
    dp(1,0);
    for(ll i=1;i<=n;++i)cnt=max(cnt,s[i]);
    printf("%lld\n",sum-cnt);
    return 0;
}
View Code

 

posted @ 2019-10-03 10:17  chdy  阅读(154)  评论(0编辑  收藏  举报