2017.11.03离线赛总结

来源:互联网 发布:淘宝菜鸟驿站怎么没了 编辑:程序博客网 时间:2024/06/08 14:54

excellent ——3802

思路:首先显然可以看出是枚举i个a,得到n-i个b,但组合数只有70,而且还有mod,那么当然要通过逆元+费马小定理来快速幂掉。

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<cstdlib>#include<algorithm>#include<vector>#include<queue>using namespace std;#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)#define LL long long #define db double#define INF 0x3f3f3f3f#define inf 0x7fffffff#define mcl(a,b) memset(a,b,sizeof(a))#define Sz(a) sizeof(a)#define pb push_back#define N 1000005#define P 1000000007int a,b,n;bool check(int x){    while(x>0){        int y=x%10;        if(y!=a && y!=b)return 0;        x/=10;    }    return 1;}struct p40{    int ans;    void dfs(int x,int sum){        if(x==n){            if(check(sum)){                ans++;                if(ans>=P)ans-=P;            }            return;        }        dfs(x+1,sum+a);        dfs(x+1,sum+b);    }    void solve(){        dfs(0,0);        cout<<ans<<endl;    }}p40;struct p70{    int ans;    int C[1505][1505];    void Init(){        C[0][0]=1;        REP(i,1,1500){            C[i][0]=1;            REP(j,1,i)(C[i][j]=C[i-1][j-1]+C[i-1][j])%=P;        }    }       void solve(){        Init();        REP(i,0,n){            int x=a*i+b*(n-i);            if(check(x)){                ans+=C[n][i];                if(ans>=P)ans-=P;            }        }        cout<<ans<<endl;    }}p70;struct p100{    LL Pow(LL x,LL y){        LL res=1;        while(y>0){            if(y&1)(res*=x)%=P;            x=x*x%P;y>>=1;        }        return res;    }    LL fac[N];    void solve(){        fac[0]=1;        REP(i,1,n)fac[i]=fac[i-1]*i%P;        LL ans=0;        REP(i,0,n){            int x=a*i+b*(n-i);            if(!check(x))continue;            ans+=fac[n]*Pow(fac[n-i],P-2)%P*Pow(fac[i],P-2)%P,ans%=P;        }        cout<<ans<<endl;    }}p100;int main(){//  freopen("excellent.in","r",stdin);//  freopen("excellent.out","w",stdout);    cin>>a>>b>>n;    if(n<=15)p40.solve();    else if(n<=1000)p70.solve();    else p100.solve();    return 0;}

num ——3803

思路:赤裸裸的dp,也比较好定义的——dp[i][j]表示上一个截点的位置为j,当前的数字串为j+1i。但这样还不够(只有70),还需要后缀数组优化一下(kmp)。

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<cstdlib>#include<algorithm>#include<vector>#include<queue>using namespace std;#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)#define LL long long #define db double#define INF 0x3f3f3f3f#define inf 0x7fffffff#define mcl(a,b) memset(a,b,sizeof(a))#define Sz(a) sizeof(a)#define pb push_back#define N 3004#define P 1000000007int n;char s[N];int dp[N][N];struct P80{    bool Cmp(int x,int y,int len){        while(len && s[x]==s[y])x++,y++,len--;        if(len)return s[x]<s[y];        return 0;    }    void solve(){        int tmp;        if(s[1]!='0')REP(i,1,n)dp[1][i]=1;        REP(i,1,n)REP(j,i,n-1)if((tmp=dp[i][j]) && s[j+1]!='0'){            int len=j-i+1;            if(j+len<=n && Cmp(i,j+1,len))(dp[j+1][j+len]+=tmp)%=P;            REP(k,j+len+1,n)(dp[j+1][k]+=tmp)%=P;        }        int ans=0;        REP(i,1,n)(ans+=dp[i][n])%=P;        cout<<ans<<endl;    }}p80;struct p100{    int mark[N][N];    void Init(){        DREP(i,n,1){            DREP(j,n,1){                if(s[i]>s[j])mark[i][j]=i;                else if(s[i]<s[j])mark[i][j]=0;                else mark[i][j]=mark[i+1][j+1];            }        }    }    void solve(){        Init();        REP(i,1,n)dp[1][i]=1;        REP(i,2,n){            if(s[i]=='0')continue;            for(int j=i,k=i-1;j<=n && k;j++,k--){                if(s[k]=='0')continue;                if(mark[i][k] && mark[i][k]<=j)(dp[i][j]+=dp[k][i-1])%=P;                else (dp[i][j+1]+=dp[k][i-1])%=P;            }            REP(j,i+1,n)(dp[i][j]+=dp[i][j-1])%=P;        }        LL ans=0;        REP(i,1,n)(ans+=dp[i][n])%=P;        cout<<ans<<endl;    }}p100;int main(){//  freopen("num.in","r",stdin);//  freopen("num.out","w",stdout);    cin>>n;    scanf("%s",s+1);    if(n<1000)p80.solve();    else p100.solve();    return 0;}

tree ——3804

思路:题意十分清晰,简而言之,就是其它点到两个被选定的点的最大距离。
由链的情况——答案应为max(a1,nb,mid(ba>>1))
引发我们思考,将树抽出一条链,也就是树的直径,那么答案同理,即a左边的所有点到a的最大距离,b右边的所有点到b的最大距离,以及a,b之间的所有点到a,b的最小值的最大值。这里两边的点都比较好处理,而中间的点需要再求出直径上a,b之间的点到其子树的每个点的距离,也就是max(min(dis[top]dis[a],dis[b]dis[top])+dep[x])

然而实现起来就比较困难了。
1.距离要倍增算,而且还要每个点向上跳和向下跳都要算出来。(蒟蒻我还没来得及写…)
2.也可以线段树来维护。

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<cstdlib>#include<algorithm>#include<vector>#include<queue>using namespace std;#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)#define LL long long #define db double#define INF 0x3f3f3f3f#define inf 0x7fffffff#define mcl(a,b) memset(a,b,sizeof(a))#define Sz(a) sizeof(a)#define pb push_back#define lson L,mid,p<<1#define rson mid+1,R,p<<1|1#define family tree[p],tree[p<<1],tree[p<<1|1]#define root 1,n,1 #define N 100000int n,m;int A[N],B[N];int D[N],son[N],fa[N],top[N],sz[N];vector<int>E[N];void dfs1(int x,int f){    sz[x]=1;    D[x]=D[f]+1;    fa[x]=f;    son[x]=0;    REP(i,0,E[x].size()-1){        int y=E[x][i];        if(y==f)continue;        dfs1(y,x);        sz[x]+=sz[y];        if(sz[y]>sz[son[x]])son[x]=y;    }}void dfs2(int x,int tp){    top[x]=tp;    if(son[x])dfs2(son[x],tp);    REP(i,0,E[x].size()-1){        int y=E[x][i];        if(y==fa[x] || y==son[x])continue;        dfs2(y,y);      }}int Lca(int a,int b){    while(top[a]!=top[b]){        if(D[top[a]]<D[top[b]])swap(a,b);        a=fa[top[a]];    }    return D[a]<D[b]?a:b;}struct plist{    int Index,ID[100012];    bool check(){        REP(i,1,n)if(E[i].size()>2)return 0;        return 1;       }    void dfs(int x,int f){        ID[x]=++Index;        REP(i,0,E[x].size()-1){            int V=E[x][i];            if(V==f) continue;            dfs(V,x);        }    }    void solve(){        int s=0;        for(int i=1;i<=n;i++)if(E[i].size()==1){s=i;break;}        Index=0;        dfs(s,s);        REP(i,1,m){            int a,b;            int ans=0;            a=ID[A[i]],b=ID[B[i]];            if(a>b) swap(a,b);            ans=max(a-1,n-b);            ans=max(ans,(b-a)>>1);            printf("%d\n",ans);        }    }}p_list;struct p30{    void solve(){        dfs1(1,0);        dfs2(1,1);        REP(i,1,m){            int a=A[i],b=B[i];            int ans=0;            REP(j,1,n){                int lca1=Lca(a,j),lca2=Lca(b,j);                int s1=D[a]+D[j]-D[lca1]*2;                int s2=D[b]+D[j]-D[lca2]*2;                ans=max(ans,min(s1,s2));            }            printf("%d\n",ans);        }    }}p30;int Mxval[N];struct p100{    int d,Dx,Rx,s;    int Id[N],dis[N],is_D[N],Link[N];    struct Tree{        struct node{            int L,R,mx;        }tree[N<<2];        void build(int L,int R,int p,int x){            tree[p].L=L,tree[p].R=R;            if(L==R){                tree[p].mx=Mxval[L]+L*x;                return;            }             int mid=(L+R)>>1;            build(lson,x),build(rson,x);            tree[p].mx=max(tree[p<<1].mx,tree[p<<1|1].mx);         }         int query(int L,int R,int p){            if(tree[p].L==L && tree[p].R==R)return tree[p].mx;            int mid=(tree[p].L+tree[p].R)>>1;            if(R<=mid)return query(L,R,p<<1);            else if(L>mid)return query(L,R,p<<1|1);            else return max(query(lson),query(rson));         }    }Tree[2];    void dfs(int x,int f,int cost){        if(cost>d)d=cost,Dx=x;        fa[x]=f;        REP(i,0,E[x].size()-1){            int y=E[x][i];            if(y==f)continue;            dfs(y,x,cost+1);        }    }    int k;    void Dfs(int x,int f,int cost){        Id[x]=k;        dis[x]=cost;        if(cost>Mxval[k])Mxval[k]=cost;        REP(i,0,E[x].size()-1){            int y=E[x][i];            if(y==f || is_D[y])continue;            Dfs(y,x,cost+1);        }     }    void Setid(){        int a=Dx;        while(a!=Rx){            is_D[a]=1;            Link[++s]=a;            a=fa[a];        }        Link[++s]=a;        is_D[a]=1;        REP(i,1,s){            k=i;            Dfs(Link[i],0,0);        }    }    void solve(){        d=-1;        dfs(1,0,0);        Rx=Dx,d=-1;        dfs(Rx,0,0);        Setid();         Tree[0].build(1,s,1,1);        Tree[1].build(1,s,1,-1);         REP(i,1,m){            int a=A[i],b=B[i];            if(Id[b]<Id[a])swap(a,b);            int x=(Id[a]+Id[b]+dis[b]-dis[a])/2;            int ans=0;            if(Id[a]==Id[b]){                ans=min(dis[a],dis[b])+Id[a]-1;                ans=max(s+min(dis[a],dis[b])-Id[a],ans);                printf("%d\n",ans);                continue;            }else {                int tmp1=min(dis[a]+Id[a]-1,dis[b]+Id[b]-1);                int tmp2=min(dis[a]+s-Id[a],dis[b]+s-Id[b]);                ans=max(tmp1,tmp2);            }            if(Id[a]<min(Id[b],x))ans=max(ans,Tree[0].query(Id[a]+1,min(Id[b],x),1)-Id[a]+dis[a]);            if(max(Id[a],x+1)<Id[b])ans=max(ans,Tree[1].query(max(Id[a],x+1),Id[b]-1,1)+Id[b]+dis[b]);            printf("%d\n",ans);        }     }}p100;int main(){//  freopen("tree.in","r",stdin);//  freopen("tree.out","w",stdout);    cin>>n;    REP(i,1,n-1){        int a,b;        scanf("%d%d",&a,&b);        E[a].pb(b);E[b].pb(a);    }    cin>>m;    REP(i,1,m)scanf("%d%d",&A[i],&B[i]);//  if(n<=2000)p30.solve();//  else if(p_list.check())p_list.solve();//  else p100.solve();    p100.solve();    return 0;}

小结:今天考得不是很好,第1题逆元没想到,第3题链写错了…(代码功底还要加强呀!)

原创粉丝点击