学大伟业 2017 国庆 Day1

 期望得分:100+100+20=220

实际得分:100+100+20=220

(好久没有期望==实际了 ,~\(≧▽≦)/~)

 

对于 a。。。。。。。。a

如果 第1个a 后面出现的第1个b~z 是右端点,且在第2个a之前,那么有贡献

如果 第2个a 前面出现的第1个b~z 是左端点,且在第1个a之后,那么有贡献

最后的贡献/2

 

#include<cstdio>
#include<cstring>

#define N 100001
 
using namespace std;

char s[N];

int LAST[26],last[N],pre[N][26],suf[N][26];
bool w[N],c[26];
 
int main()
{
    freopen("cross.in","r",stdin);
    freopen("cross.out","w",stdout);
    scanf("%s",s+1);
    int len=strlen(s+1),ans=0,ch;
    
    for(int i=1;i<=len;i++)
        for(int j=0;j<26;j++)
            if(s[i]-'a'==j) pre[i][j]=i;
            else pre[i][j]=pre[i-1][j];
    
    for(int i=0;i<26;i++) suf[len][i]=len+1;
    suf[len][s[len]-'a']=len;
    for(int i=len-1;i;i--)
        for(int j=0;j<26;j++)
            if(s[i]-'a'==j) suf[i][j]=i;
            else suf[i][j]=suf[i+1][j];
    
    for(int i=1;i<=len;i++)
    {
        ch=s[i]-'a';
        c[ch]^=1; w[i]=!c[ch];
        if(c[ch]) LAST[ch]=i;
        else last[i]=LAST[ch];
    }
    
    for(int i=1;i<=len;i++)
        if(w[i])
        {
            for(int j=0;j<26;j++)
                if(j!=s[i]-'a')
                {
                    if(suf[last[i]][j]<i && w[suf[last[i]][j]]) ans++;
                    if(pre[i][j]>last[i] && !w[pre[i][j]]) ans++;
                }
        }
        
    printf("%d",ans>>1);
}
View Code

 

 

dis[i][j] 表示 到第i个点,用了j次传送的最快时间

堆优化的dijkstra

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 501
#define M 2001

int n,m,g,k;

int front[N],to[M<<1],nxt[M<<1],val[M<<1],tot;
bool fly[M<<1];

int DIS[N][2001];

struct node
{
    int tim,dis,num;
    bool operator < (node p) const
    {
        return dis>p.dis;
    }
}cur,nt;

priority_queue<node>q;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v,int w,bool fl)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w; fly[tot]=fl;
}

void init()
{
    read(n); read(m); read(g); read(k);
    int u,v,w;
    k=min(g,k);
    while(m--)
    {
        read(u); read(v); read(w);
        add(u,v,w,0);
    }
    while(g--)
    {
        read(u); read(v); read(w);
        add(u,v,w,1);
    }
}

void dijkstra()
{
    memset(DIS,63,sizeof(DIS));
    cur.dis=0; cur.num=1; cur.tim=0;
    DIS[1][0]=0;
    q.push(cur);
    while(!q.empty())
    {
        cur=q.top(); q.pop();
        if(cur.num==n)
        {
            printf("%d",cur.dis);
            return;
        }
        if(DIS[cur.num][cur.tim]!=cur.dis) continue;
        for(int i=front[cur.num];i;i=nxt[i])
        {
            if(DIS[to[i]][cur.tim+fly[i]]<cur.dis+val[i]) continue;
            if(cur.tim+fly[i]>k) continue;
            DIS[to[i]][cur.tim+fly[i]]=cur.dis+val[i];
            nt.dis=cur.dis+val[i];
            nt.tim=cur.tim+fly[i];
            nt.num=to[i];
            q.push(nt);
        }
    }
    printf("-1");
}

int main()
{
    freopen("move.in","r",stdin);
    freopen("move.out","w",stdout);
    init();
    dijkstra();
    return 0;
}
View Code

 

 

相当于把树分成许多块,每一个块的大小>=k,求分块方案数

树上背包

dp[i][j] 以i为根子树内,块的大小为j的方案数

g[j] 当前大小为j的块的方案数

cnt[i] 以i为根节点的块,大小>=k的方案数

 

假设当前正在合并u的子节点 v

v所在块 如果本身就>=k,那么v可以不并入u,g[j]=cnt[v]*dp[u][j]

枚举已经与u合并的块的大小j

枚举v所在块的大小h

g[j+h]+=dp[x][j]*dp[v][h]

合并u和v,把g赋给dp

 

最后处理完u的时候更新cnt

 

注意师最后合并,这样可以使时间复杂度降到 n^2

相当于每对点只在LCA处有贡献

 

 

#include<cstdio>
#include<iostream>

using namespace std;

#define N 5001
#define mod 786433

int front[N],to[N<<1],nxt[N<<1],tot;

int siz[N],dp[N][N],g[N],cnt[N];

int k;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}

void init()
{
    int n;
    read(n); read(k);
    int u,v;
    for(int i=1;i<n;i++)
    {
        read(u); read(v);
        add(u,v);
    }
}

void dfs(int x,int y)
{
    siz[x]=1;
    dp[x][1]=1;
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=y)
        {
            dfs(to[i],x);
            for(int j=1;j<=siz[x]+siz[to[i]];j++) g[j]=0;
            for(int j=1;j<=siz[x];j++) g[j]=1ll*cnt[to[i]]*dp[x][j]%mod;
            for(int j=1;j<=siz[x];j++)
                for(int h=1;h<=siz[to[i]];h++)
                    g[j+h]=(g[j+h]+1ll*dp[x][j]*dp[to[i]][h]%mod)%mod;
            for(int j=1;j<=siz[x]+siz[to[i]];j++) dp[x][j]=g[j];
            siz[x]+=siz[to[i]];
        }
    for(int i=k;i<=siz[x];i++) cnt[x]+=dp[x][i],cnt[x]%=mod;
}

int main()
{
    freopen("cut.in","r",stdin);
    freopen("cut.out","w",stdout);
    init();
    dfs(1,0);
    int ans=0;
    for(int i=k;i<=siz[1];i++) ans+=dp[1][i],ans%=mod;
    printf("%d",ans);
}
View Code

 

 

 

2^n  20分暴力

 

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 5001

int n,k;

int front[N],to[N<<1],nxt[N<<1],from[N<<1],tot;

int ans,cnt;

bool use[N];

int siz[N];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v;
}

void init()
{
    read(n); read(k);
    int u,v;
    for(int i=1;i<n;i++)
    {
        read(u); read(v);
        add(u,v);
    }
}

void dfs2(int x,int y)
{
    cnt++;
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=y && use[i]) dfs2(to[i],x);
}

void judge()
{
    for(int i=1;i<=n;i++)
    {
        cnt=0;
        dfs2(i,0);
        if(cnt<k) return;
    }
    ans++;
}

void dfs(int x)
{
    if(x==(n-1)*2+1) 
    {
        judge();
        return;
    }
    dfs(x+2);
    use[x]=use[x+1]=true; dfs(x+2); use[x]=use[x+1]=false;
}

int main()
{
    freopen("cut.in","r",stdin);
    freopen("cut.out","w",stdout);
    init();
    dfs(1);
    printf("%d",ans); 
}
View Code

 

posted @ 2017-10-23 16:25  TRTTG  阅读(374)  评论(0编辑  收藏  举报