2017.11.03离线赛总结

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 1000000007

int 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+1 i 。但这样还不够(只有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 1000000007

int 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 100000

int 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题链写错了…(代码功底还要加强呀!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值