2018.9.4离线赛总结

T1——happy(2958)

Description:

定义一个数为 happy h a p p y ,即只有一位上的数与其它位上的数不同,询问 [a,b] [ a , b ] happy h a p p y 数的个数.
ab1016 a ≤ b ≤ 10 16

Solution:

  • 刚刚开始还以为是数位 dp d p ,
  • 敲完暴力发现只要枚举位数构造一下再判一下是否在 [a,b] [ a , b ] 中即可.

Code:

#include
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(A) sizeof(A)
#define mcl(A,b) memset(A,b,Sz(A))
#define mcp(A,b) memcpy(A,b,Sz(b))
#define pb push_back
#define fi first
#define se second
templateinline bool chkmin(T &x,T y){return y1:0;}
templateinline bool chkmax(T &x,T y){return x1:0;}
typedef pair<int,int>PII;

#define N 18

ll a,b;

struct p100{

    int get(ll x){
        int cnt=0;
        while(x){
            cnt++;
            x/=10;
        }
        return cnt;
    }

    ll change(int len,int pos,int x,int y){
        ll num=0;
        if(!x && pos>1 || !y && pos==1)return 0;
        SREP(i,1,pos)num=num*10+x;
        num=num*10+y;
        REP(i,pos+1,len)num=num*10+x;
        return num;
    }

    ll calc(int top){
        ll res=0;
        SREP(i,0,10) SREP(j,0,10) if(i!=j){
            REP(k,1,top){
                ll tmp=change(top,k,i,j);
                if(a<=tmp && tmp<=b)res++;
            }
        }
        return res;
    }

    void solve(){
        int len1=get(a);
        int len2=get(b);
//      printf("len1=%d len2=%d\n",len1,len2);
        ll ans=0;
        REP(i,len1,len2){
            if(i<2)continue;
            if(i==2)SREP(j,10,100)ans+=(j>=a && j<=b);
            else ans+=calc(i);
        }
        printf("%lld\n",ans);
    }
}p2;

int main(){
//  freopen("happy.in","r",stdin);
//  freopen("happy.out","w",stdout);
    scanf("%lld%lld",&a,&b);
    p2.solve();
    return 0;
}

T2——paint(3113)

Description:

[1,n] [ 1 , n ] 球中染色,使任意 [i,i+m1] [ i , i + m − 1 ] 内都至少有 2 2 个球被染色,染色代价为 c[i] c [ i ] .
n20000,m2000,ci20000 n ≤ 20000 , m ≤ 2000 , c i ≤ 20000

Solution:

  • 不难想到一个比较暴力的做法: dp[i][j]= d p [ i ] [ j ] = min { dp[j][k]|i>j>k>=im d p [ j ] [ k ] | i > j > k >= i − m } +c[i] + c [ i ] ,表示当前给第i个球染色,上一个染色的是第j个球的最小花费.
  • 这样就是 Θ(nm2) Θ ( n m 2 ) ,分析一下上式,发现 min(dp[j][k]) m i n ( d p [ j ] [ k ] ) 应该会有很多事重复的,
  • 于是就想到固定 j j ,
  • 那么 i[j+1,j+m1],k[jm+1,j1] i ∈ [ j + 1 , j + m − 1 ] , k ∈ [ j − m + 1 , j − 1 ]
  • 那么我们倒推 i i , min(dp[j][k]) m i n ( d p [ j ] [ k ] ) 需要计算的范围就会依次变大.
  • 即可 Θ(1) Θ ( 1 ) 转移,那么整个 Θ(nm) Θ ( n m )

Code:

#include
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(A) sizeof(A)
#define mcl(A,b) memset(A,b,Sz(A))
#define mcp(A,b) memcpy(A,b,Sz(b))
#define pb push_back
#define fi first
#define se second
templateinline bool chkmin(T &x,T y){return y1:0;}
templateinline bool chkmax(T &x,T y){return x1:0;}
typedef pair<int,int>PII;

#define N 20002
#define M 2001

int n,m;
int c[N];

struct p30{

    bool mark[22];

    bool check(){
        REP(i,1,n-m+1){
            int cnt=0;
            REP(j,i,i+m-1)cnt+=mark[j];
            if(cnt<2)return 0;
        }
        return 1;
    }

    void solve(){

        int ans=INF;

        SREP(s,0,1<0);
            SREP(i,0,n) if(s&(1<1]=1;
            if(check()){
                int sum=0;
                REP(i,1,n) if(mark[i]) sum+=c[i];
                chkmin(ans,sum);
            }               
        }

        printf("%d\n",ans);
    }
}p1;

struct p100{

    int dp[M+5][M+5];

    void solve(){
        mcl(dp,INF);
        REP(i,1,m) SREP(j,1,i) dp[i][j]=c[i]+c[j];

        SREP(j,2,n){
            int mn=INF;
            for(int i=j+m-1;i>j && i>m;--i){
                chkmin(mn,dp[j%M][(i-m)%M]);
                dp[i%M][j%M]=mn+c[i];
            }
        }
        int ans=INF;
        REP(i,n-m+1,n) for(int j=i-1;i-j"%d\n",ans);
    }
}p2;

struct p60{

    int dp[502][502];

    void solve(){
        mcl(dp,INF);
        REP(i,1,m)dp[i][0]=c[i];

        REP(i,1,n+1) SREP(j,max(0,i-m+1),i) SREP(k,max(0,i-m),j) chkmin(dp[i][j],dp[j][k]+c[i]);

        int ans=INF;
        REP(i,0,n) chkmin(ans,dp[n+1][i]);
        printf("%d\n",ans);
    }
}p3;

int main(){
//  freopen("paint.in","r",stdin);
//  freopen("paint.out","w",stdout);
    scanf("%d%d",&n,&m);
    REP(i,1,n) scanf("%d",&c[i]);

    if(n<=20)p1.solve();
    else if(n<=500 && m<=100)p3.solve();
    else p2.solve();
    return 0;
}

T3——repair(3006)

Description:

求一棵树上条不相交的路径的长度的乘积的最大值.
n105 n ≤ 10 5

Solution:

  • 很容易就想到将一条边切掉,求剩下两棵树的直径.这样就是 Θ(n2) Θ ( n 2 )
  • 但要达到线性,也不难看出是一道树形 dp d p ,那么再想一下 dp d p 的状态,
  • dp[x][1/2/3] d p [ x ] [ 1 / 2 / 3 ] 分别表示以x为根的子树的次长链值,最长链值,乘积最大值.

Code:

#include
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(A) sizeof(A)
#define mcl(A,b) memset(A,b,Sz(A))
#define mcp(A,b) memcpy(A,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y1:0;}
template<class T>inline bool chkmax(T &x,T y){return x1:0;}
typedef pair<int,int>PII;

#define N 100002

int n;
vector<int>E[N];

struct p20{

    int sz[N],son[N],fa[N],dep[N],top[N];

    void dfs1(int x,int f){
        sz[x]=1;
        son[x]=0;
        fa[x]=f;
        dep[x]=dep[f]+1;
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(y==f)continue;
            dfs1(y,x);
            sz[x]+=sz[y];
            if(sz[son[x]]void dfs2(int x,int tp){
        top[x]=tp;
        if(son[x])dfs2(son[x],tp);
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(y==fa[x] || y==son[x])continue;
            dfs2(y,y);
        }
    }

    int Lca(int x,int y){
        while(top[x]!=top[y]){
            if(dep[top[x]]return dep[x]bool mark[22];

    void push(int x,int y,int lca){
        mcl(mark,0);
        while(x!=lca){
            mark[x]=1;
            x=fa[x];
        }
        while(y!=lca){
            mark[y]=1;
            y=fa[y];
        }
        mark[lca]=1;
    }

    bool check(int x,int y,int lca){
        if(mark[lca])return 0;
        while(x!=lca){
            if(mark[x])return 0;
            x=fa[x];
        }
        while(y!=lca){
            if(mark[y])return 0;
            y=fa[y];
        }
        return 1;
    }

    void solve(){
        dfs1(1,0);
        dfs2(1,1);
        ll ans=0;
        REP(x1,1,n) REP(y1,x1+1,n) REP(x2,1,n) REP(y2,x2+1,n) {
            int lca1=Lca(x1,y1),lca2=Lca(x2,y2);
            push(x1,y1,lca1);
            if(check(x2,y2,lca2)){ 
                int d1=dep[x1]+dep[y1]-2*dep[lca1];
                int d2=dep[x2]+dep[y2]-2*dep[lca2];
                chkmax(ans,1ll*d1*d2);
            }
        }
        printf("%lld\n",ans);
    }
}p1;

struct p2{

    ll dp[N][5];
    ll ans;

    void update(int x,int op,int &m1,int &m2){
        ll t=dp[x][op]+1;
        if(t>m1)m2=m1,m1=t;
        else if(t>m2)m2=t;
    }

    void dfs1(int x,int f){
        int mx1=0,mx2=0,len1=0,len2=0;
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(y==f)continue;
            dfs1(y,x);
            chkmax(dp[x][1],dp[y][1]+1);
            chkmax(dp[x][3],dp[y][3]);
            chkmax(dp[x][2],dp[y][2]);
            update(y,1,mx1,mx2);
            update(y,2,len1,len2);
        }
        chkmax(dp[x][2],1ll*(mx1+mx2));
        chkmax(dp[x][3],1ll*len1*len2);
    }

    void dfs2(int x,int f,int ye,int tmp){
        int mx1=0,mx2=0,t=0;
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(y==f)continue;
            if(dp[y][1]+1>mx1)mx2=mx1,mx1=dp[y][1]+1,t=y;
            else if(dp[y][1]+1>mx2)mx2=dp[y][1]+1;
        }
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(y==f)continue;
            int num=max(tmp,ye+(int)(y==t?mx2:mx1));
            chkmax(ans,dp[y][2]*num);
            dfs2(y,x,max((int)(y==t?mx2:mx1),ye)+1,num);
        }
    }

    void solve(){
        dfs1(1,0);
        ans=dp[1][3];
        dfs2(1,0,0,0);
        printf("%lld\n",ans);
    }
}p2;

PII em[N];
struct p80{

    int id1,id2;
    int len1,len2;

    void dfs1(int x,int f,int sum){
        if(chkmax(len1,sum))id1=x;
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(y==f || mp[x][y])continue;
            dfs1(y,x,sum+1);
        }
    }

    void dfs2(int x,int f,int sum){
        chkmax(len1,sum);
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(y==f || mp[x][y])continue;
            dfs2(y,x,sum+1);
        }
    }

    void dfs3(int x,int f,int sum){
        if(chkmax(len2,sum))id2=x;
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(y==f || mp[x][y])continue;
            dfs3(y,x,sum+1);
        }
    }

    void dfs4(int x,int f,int sum){
        chkmax(len2,sum);
        SREP(i,0,E[x].size()){
            int y=E[x][i];
            if(y==f || mp[x][y])continue;
            dfs4(y,x,sum+1);
        }
    }

    map<int,bool>mp[N];

    void solve(){

        ll ans=0;
        SREP(i,1,n){
            int a=em[i].fi,b=em[i].se;
            mp[a][b]=mp[b][a]=1;

            len1=len2=0;
            id1=a,id2=b;

            dfs1(a,0,0);
            dfs2(id1,0,0);

            dfs3(b,0,0);
            dfs4(id2,0,0);

            chkmax(ans,1ll*len1*len2);

            mp[a][b]=mp[b][a]=0;
        }
        printf("%lld\n",ans);
    }
}p3;

int main(){
//  freopen("repair.in","r",stdin);
//  freopen("repair.out","w",stdout);
    scanf("%d",&n);
    SREP(i,1,n){
        int a,b;
        scanf("%d%d",&a,&b);
        em[i]=(PII){a,b};
        E[a].pb(b);
        E[b].pb(a);
    }
    if(n<=20)p1.solve();
    else if(n<=1000)p3.solve();
    else p2.solve();
    return 0;
}

Summary:

  • 标准的联赛难度.
  • 大概暴力就可以做到100+60+70=230.
  • 然后T3的树形dp也比较套路,最后还是调出来了.来说数据有点水,好像还是打错了一个字符就是100+60+100=260.

你可能感兴趣的:(离线赛-总结)