2019年8月6日(基本功练习3)

看到\(DP\)就死了!!

prob1:中位数图

傻逼题,,,

因为是\(1\)\(n\)的排列,所以我们可以准确的找到\(b\)的位置,设该位置下标为\(i\),从\(a_{i-1}\)的到\(a_1\)遍历一遍,\(a_j<b\)\(smaller_j=smaller_{j+1}+1\)\(bigger_j\)继承\(bigger_{j+1}\),不变,若\(a_j>b\)则反之。同理,从\(i+1\)\(n\)同样如此操作,这样就好出答案了……

明显,包含\(b\)的区间要不就以\(i\)为左界或右界,要不就将\(i\)包含在中间。若是前者,统计\(bigger_j=smaller_j\)的数量,对于后者,设左界为\(j\),右界为\(k\),则显然满足\(bigger_j+bigger_k=smaller_j+smaller_k\),移项得到\(bigger_j-smaller_j=smaller_k-bigger_k\),开个桶\(cnt\)统计一下就好了。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
    int x=0;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar());
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}
const int xx=1e5+10;
int a[xx],ans_place;
int bigger[xx],smaller[xx],cnt[xx<<1];
jinitaimei main()
{
    int n=in,b=in,ans=0;
    fur(i,1,n)
    {
        a[i]=in;
        if(a[i]!=b) continue;
        ans_place=i;
    }
    fdr(i,ans_place-1,1)
    {
        if(a[i]>b) smaller[i]=smaller[i+1],bigger[i]=bigger[i+1]+1;
        if(a[i]<b) smaller[i]=smaller[i+1]+1,bigger[i]=bigger[i+1];
    }
    fur(i,ans_place+1,n)
    {
        if(a[i]>b) smaller[i]=smaller[i-1],bigger[i]=bigger[i-1]+1;
        if(a[i]<b) smaller[i]=smaller[i-1]+1,bigger[i]=bigger[i-1];
    }
    fur(i,1,n) if(bigger[i]==smaller[i]) ++ans;
    fur(i,ans_place+1,n) ++cnt[xx+smaller[i]-bigger[i]];
    fur(i,1,ans_place-1) ans+=cnt[xx+bigger[i]-smaller[i]];
    printf("%lld\n",ans);
    return 0;
}

prob2:树

其实这题才是最水的,可惜我调倍增调了半天……

但这题暴力能过。表示不会证明复杂度,是数据太水了吗QWQ……

很明显点权都是正整数,链又得是连续的,所以当当前链的\(sum>s\)时,跳最深一个可以使\(sum_i-sum_{fa}<=s\)的进行删减,再统计答案。

思路很简单,暴力更简单(时间复杂度\(O(n^2)\),怀疑跑不满):

#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
    int x=0;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar());
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}
const int xx=1e5+10;
bool root[xx];
vector<int>e[xx];
struct point{int fa,sum,w,dep;}dot[xx];
int k,n,rt,ans=0;
inline void dfs(int g)
{
    if(dot[g].sum==k) ++ans;
    if(dot[g].sum>k)
    {
        int jump=g;
        while(dot[g].sum-dot[jump].sum<k) jump=dot[jump].fa;
        if(dot[g].sum-dot[jump].sum==k) ++ans;
    }
    fur(i,0,(int)e[g].size()-1)
    {
        dot[e[g][i]].fa=g;
        dot[e[g][i]].dep=dot[g].dep+1;
        dot[e[g][i]].sum=dot[g].sum+dot[e[g][i]].w;
        dfs(e[g][i]);
    }
}
jinitaimei main()
{
    n=in;k=in;
    fur(i,1,n) dot[i].w=in;
    fur(i,1,n-1)
    {
        int x=in,y=in;
        e[x].push_back(y);
        dot[y].fa=x;
        root[y]=true;
    }
    fur(i,1,n) if(!root[i]) rt=i;
    dot[rt].sum=dot[rt].w;
    dfs(rt);
    printf("%lld\n",ans);
    return 0;
}

倍增(调了半天),时间复杂度(\(O(nlogn)\),但好像没暴力快):

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
    int x=0;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar());
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}
const int xx=1e5+10;
bool root[xx];
vector<int>e[xx];
struct point{int fa[18],sum,w,dep;}dot[xx];
int k,n,rt,ans=0;
inline void dfs(int g)
{
    if(dot[g].sum==k) ++ans;
    if(dot[g].sum>k)
    {
        int jump=g;
        fdr(i,17,0) if(dot[g].sum-dot[dot[jump].fa[i]].sum<k&&dot[g].fa[i]) jump=dot[jump].fa[i];
        if(dot[g].sum-dot[dot[jump].fa[0]].sum==k) ++ans;
    }
    fur(i,0,(int)e[g].size()-1)
    {
        dot[e[g][i]].fa[0]=g;
        dot[e[g][i]].dep=dot[g].dep+1;
        dot[e[g][i]].sum=dot[g].sum+dot[e[g][i]].w;
        fur(j,1,17) dot[e[g][i]].fa[j]=dot[dot[e[g][i]].fa[j-1]].fa[j-1];
        dfs(e[g][i]);
    }
}
jinitaimei main()
{
    n=in;k=in;
    fur(i,1,n) dot[i].w=in;
    fur(i,1,n-1)
    {
        int x=in,y=in;
        e[x].push_back(y);
        dot[y].fa[0]=x;
        root[y]=true;
    }
    fur(i,1,n) if(!root[i]) rt=i;
    dot[rt].sum=dot[rt].w;
    dfs(rt);
    printf("%lld\n",ans);
    return 0;
}

prob5:松鼠的新家

额,树剖板子题?

其实可以\(Tarjan\)\(lca\)再树上差分,可以\(O(n)\)

扫描二维码关注公众号,回复: 6970926 查看本文章

可好久没写\(Tarjan\)了……

先给差分代码吧(用的是树剖跳\(lca\)):

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define int long long
#define jinitaimei signed
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
const int xx=3e5+10;
int cf[xx],a[xx];
struct point{int top,son,fa,dep,sz;bool vis;}dot[xx];
vector<int>e[xx];
inline void dfs1(int g)
{
    dot[g].sz=1;
    fur(i,0,(int)e[g].size()-1)
    {
        if(dot[e[g][i]].vis) continue;
        dot[e[g][i]].vis=true;
        dot[e[g][i]].fa=g;
        dot[e[g][i]].dep=dot[g].dep+1;
        dfs1(e[g][i]);
        dot[g].sz+=dot[e[g][i]].sz;
        if(dot[e[g][i]].sz>dot[dot[g].son].sz) dot[g].son=e[g][i];
    }
}
inline void dfs2(int g,int gg)
{
    dot[g].top=gg;
    if(dot[g].son) dfs2(dot[g].son,gg);
    fur(i,0,(int)e[g].size()-1) if(e[g][i]!=dot[g].fa&&e[g][i]!=dot[g].son) dfs2(e[g][i],e[g][i]);
}
inline void dfs3(int g)
{
    fur(i,0,(int)e[g].size()-1)
    {
        if(e[g][i]==dot[g].fa) continue;
        dfs3(e[g][i]);
        cf[g]+=cf[e[g][i]];
    }
}
inline int lca(int u,int v)
{
    while(dot[u].top!=dot[v].top)
    {
        if(dot[dot[u].top].dep<dot[dot[v].top].dep) swap(u,v);
        u=dot[dot[u].top].fa;
    }
    return dot[u].dep<dot[v].dep?u:v;
}
jinitaimei main()
{
    int n=in;
    fur(i,1,n) a[i]=in;
    fur(i,1,n-1)
    {
        int x=in,y=in;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dot[1].vis=true;
    dfs1(1);
    dfs2(1,1);
    fur(i,1,n-1)
    {
        int q=lca(a[i],a[i+1]);
        --cf[q];
        --cf[dot[q].fa];
        ++cf[a[i]];
        ++cf[a[i+1]];
    }
    dfs3(1);
    fur(i,2,n) --cf[a[i]];
    fur(i,1,n) printf("%lld\n",cf[i]);
    return 0;
}

树剖套线段树:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define int long long
#define jinitaimei signed
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
const int xx=3e5+10;
int a[xx],cnt=0,rk[xx],ans[xx];
struct linetree{int sum,lazy,l,r;}lt[xx<<2];
struct point{int top,id,son,fa,dep,sz;bool vis;}dot[xx];
vector<int>e[xx];
inline void dfs1(int g)
{
    dot[g].sz=1;
    fur(i,0,(int)e[g].size()-1)
    {
        if(dot[e[g][i]].vis) continue;
        dot[e[g][i]].vis=true;
        dot[e[g][i]].fa=g;
        dot[e[g][i]].dep=dot[g].dep+1;
        dfs1(e[g][i]);
        dot[g].sz+=dot[e[g][i]].sz;
        if(dot[e[g][i]].sz>dot[dot[g].son].sz) dot[g].son=e[g][i];
    }
}
inline void dfs2(int g,int gg)
{
    dot[g].id=++cnt;
    rk[cnt]=g;
    dot[g].top=gg;
    if(dot[g].son) dfs2(dot[g].son,gg);
    fur(i,0,(int)e[g].size()-1) if(e[g][i]!=dot[g].fa&&e[g][i]!=dot[g].son) dfs2(e[g][i],e[g][i]);
}
inline void up(int k)
{
    int q=k<<1;
    lt[k].sum=lt[q].sum+lt[q+1].sum;
}
inline void down(int k)
{
    if(!lt[k].lazy) return;
    int q=k<<1;
    lt[q].lazy+=lt[k].lazy;
    lt[q+1].lazy+=lt[k].lazy;
    lt[q].sum+=lt[k].lazy*(lt[q].r-lt[q].l+1);
    lt[q+1].sum+=lt[k].lazy*(lt[q+1].r-lt[q+1].l+1);
    lt[k].lazy=0;
}
inline void build(int k,int i,int j)
{
    lt[k].l=i;lt[k].r=j;
    if(i==j)
    {
        lt[k].lazy=lt[k].sum=0;
        return;
    }
    int q=k<<1,mid=(i+j)>>1;
    build(q,i,mid);
    build(q+1,mid+1,j);
    up(k);
}
inline void add(int k,int i,int j)
{
    if(i<=lt[k].l&&j>=lt[k].r)
    {
        lt[k].sum+=(lt[k].r-lt[k].l+1);
        ++lt[k].lazy;
        return;
    }
    int q=k<<1,mid=lt[q].r;
    if(i<=mid) add(q,i,j);
    if(j>mid) add(q+1,i,j);
}
inline void downtown(int k)
{
    if(lt[k].l==lt[k].r)
    {
        ans[rk[lt[k].l]]=lt[k].sum;
        return;
    }
    down(k);
    int q=k<<1;
    downtown(q);
    downtown(q+1);
}
inline void change(int u,int v)
{
    while(dot[u].top!=dot[v].top)
    {
        if(dot[dot[u].top].dep<dot[dot[v].top].dep) swap(u,v);
        add(1,dot[dot[u].top].id,dot[u].id);
        u=dot[dot[u].top].fa;
    }
    if(dot[u].id>dot[v].id) swap(u,v);
    add(1,dot[u].id,dot[v].id);
}
jinitaimei main()
{
    int n=in;
    fur(i,1,n) a[i]=in;
    fur(i,1,n-1)
    {
        int x=in,y=in;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dot[a[1]].vis=true;
    dfs1(a[1]);
    dfs2(a[1],a[1]);
    build(1,1,n);
    fur(i,1,n-1) change(a[i],a[i+1]);
    downtown(1);
    fur(i,2,n) --ans[a[i]];
    fur(i,1,n) printf("%lld\n",ans[i]);
    return 0;
}

prob4:座位安排

写了好久的题解

prob3:Bill的挑战

最后一题,调到绝望。

全场就\(wyl\)巨佬切了这题,\(orz\)啊!!!

好吧,表示没看出来这是状压\(DP\).

\(f_{i,j}\)为扫描到第\(i\)位,\(j\)的二进制下为各串是否匹配的方案数。

额……

讲不下去了,,,

好吧,状压\(DP\)貌似是我死穴,还是看这位大佬的吧

贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define int long long
#define jinitaimei signed
char s[16][51];
int ch[16][51];
int f[51][1<<16];
int has[27][27*15];
const int mod=1e6+3;
inline int num(int k){int ans=0;for(;k;k>>=1) if(k&1) ++ans;return ans;}
jinitaimei main()
{
    int t;
    scanf("%lld",&t);
    while(t--)
    {
        int n,len,m;
        scanf("%lld%lld",&n,&m);
        fur(i,1,n)
        {
            scanf("%s",s[i]);
            len=strlen(s[i]);
            fur(j,0,len-1) ch[i][j]=isalpha(s[i][j])?(s[i][j]-'a'+1):27;
        }
        memset(f,-1,sizeof(f));
        memset(has,0,sizeof(has));
        f[0][(1<<n)-1]=1;
        fur(i,1,len)
        {
            fur(P,0,(1<<n)-1)
            {
                if(f[i-1][P]==-1) continue;
                fur(k,1,26) has[k][0]=0;
                fur(k,1,n)
                {
                    if((P&1<<(k-1))==0) continue;
                    if(ch[k][i-1]<27) has[ch[k][i-1]][++has[ch[k][i-1]][0]]=k;
                    else fur(j,1,26) has[j][++has[j][0]]=k;
                }
                fur(k,1,26)
                {
                    if(!has[k][0]) continue;
                    int sum=0;
                    fur(j,1,has[k][0]) sum+=(1<<(has[k][j]-1));
                    if(f[i][sum]==-1) f[i][sum]=0;
                    (f[i][sum]+=f[i-1][P])%=mod;
                }
            }
        }
        int ans=0;
        fur(i,0,(1<<n)-1)
        {
            if(num(i)!=m) continue;
            if(f[len][i]==-1) continue;
            (ans+=f[len][i])%=mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ALANALLEN21LOVE28/p/11313042.html