2017.11.04离线赛总结

来源:互联网 发布:买了域名怎么卖 编辑:程序博客网 时间:2024/06/05 17:20

foreat ——3805

思路:显然的二分答案,不解释。

robot ——3806

思路:有点不明显的状压dp(但看数据范围还是能猜出来的),状压颜色,然而还要前缀和预处理一下,并且每次找该状态的lowbit转移。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<algorithm>#include<vector>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 0x7fffffff#define INF 0x3f3f3f3f#define mcl(a,b) memset(a,b,sizeof(a))#define Sz(a) sizeof(a)#define N 100005#define M 20int n,K;int A[N];struct p20{    vector<int>E[N];    LL calc(int col){        LL ans=0;        int m=E[col].size();        if(m==1)return 0;        int x=m;        for(int i=0;i<m;i++){            int p=E[col][i];            int s=n-x+1;            ans+=s-p;            x--;            }        return ans;    }    void solve(){        for(int i=1;i<=n;i++)scanf("%d",&A[i]),E[A[i]].push_back(i);        printf("%lld\n",min(calc(1),calc(2)));    }}p20;struct p100{    int cnt[M];    LL sum[1<<M][M],last[M][M];    LL dp[1<<M];    int base[1<<M];    void Init(){        mcl(dp,INF);        REP(i,0,K-1)base[1<<i]=i,sum[0][i]=dp[1<<i]=0;    }    void solve(){        REP(i,0,n-1){            scanf("%d",&A[i]);            A[i]--;        }        Init();        DREP(i,n-1,0){            REP(j,0,K-1)if(j!=A[i])last[A[i]][j]+=cnt[j];            cnt[A[i]]++;        }        REP(i,1,(1<<K)-1){            REP(j,0,K-1){                if((i&(1<<j)))continue;                int x=i&(-i);                sum[i][j]=sum[i-x][j]+last[j][base[x]];            }        }         REP(i,0,(1<<K)-1){            REP(j,0,K-1){                if(i&(1<<j))continue;                dp[i|(1<<j)]=min(dp[i|(1<<j)],dp[i]+sum[i][j]);            }        }         cout<<dp[(1<<K)-1]<<endl;     }}p100;int main(){//    freopen("robot.in","r",stdin);//    freopen("robot.out","w",stdout);    cin>>n>>K;    if(K==2)p20.solve();    else p100.solve();    return 0;}

tree ——3807

思路:与Paths神似,两条路径是否相交,即判断一条的lca是否被另一条路径经过,那么玄学的按照lca的deep从小到大排序,最后线段树维护一下即可求出答案。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<algorithm>#include<vector>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 0x7fffffff#define INF 0x3f3f3f3f#define mcl(a,b) memset(a,b,sizeof(a))#define Sz(a) sizeof(a)#define lson L,mid,p<<1#define rson mid+1,R,p<<1|1#define root 1,n,1 #define N 100005#define M 1005int n,m;LL ans;vector<int>E[N],vis[N];int D[N],fa[N],son[N],top[N],sz[N];int sgID[N],List[N],T;int mark[M][M];struct Node{    int from,to,lca;    bool operator<(const Node &a)const{        return D[lca]<D[a.lca];     }}Q[N];void dfs1(int x,int f){    D[x]=D[f]+1;    son[x]=0;    sz[x]=1;    fa[x]=f;    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;      sgID[x]=++T;    List[T]=x;     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 p60{    void solve(){        dfs1(1,0);        dfs2(1,1);        REP(i,1,m){            int a=Q[i].from,b=Q[i].to,lca=Lca(a,b);            vis[lca].push_back(i);            while(a!=lca){                vis[a].push_back(i);                a=fa[a];            }            while(b!=lca){                vis[b].push_back(i);                b=fa[b];            }        }        LL ans=0;        REP(i,1,n){            if(vis[i].size()<2)continue;            REP(j,0,vis[i].size()-1){                REP(k,j+1,vis[i].size()-1){                    int x=vis[i][j],y=vis[i][k];                    if(x==y ||mark[x][y])continue;                    mark[x][y]=mark[y][x]=1;                    ans++;                }            }        }        cout<<ans<<endl;    }}p60;struct p100{    struct Tree{        struct node{            int L,R,sum;        }tree[N<<2];        void build(int L,int R,int p){            tree[p].L=L,tree[p].R=R;            tree[p].sum=0;            if(L==R)return;            int mid=(L+R)>>1;            build(lson),build(rson);         }        void update(int L,int R,int p){            if(tree[p].L==L && tree[p].R==R){                tree[p].sum++;                return;            }            int mid=(tree[p].L+tree[p].R)>>1;            if(R<=mid)update(L,R,p<<1);            else if(L>mid)update(L,R,p<<1|1);            else update(lson),update(rson);        }        void query(int x,int p){            ans+=tree[p].sum;            if(tree[p].L==tree[p].R)return;            int mid=(tree[p].L+tree[p].R)>>1;            if(x<=mid)query(x,p<<1);            else query(x,p<<1|1);         }    }Tree;     void change(int a,int b){        while(top[a]!=top[b]){            if(D[top[a]]<D[top[b]])swap(a,b);            Tree.update(sgID[top[a]],sgID[a],1);            a=fa[top[a]];        }        if(D[a]>D[b])swap(a,b);        Tree.update(sgID[a],sgID[b],1);     }    void solve(){        dfs1(1,0);        dfs2(1,1);        REP(i,1,m)Q[i].lca=Lca(Q[i].from,Q[i].to);        sort(Q+1,Q+1+m);        Tree.build(root);        REP(i,1,m){            Tree.query(sgID[Q[i].lca],1);            change(Q[i].from,Q[i].to);        }        cout<<ans<<endl;    }}p100;int A[N<<1]; LL cnt[N],sum[N];struct p_list{    bool check(){        REP(i,1,n)if(E[i].size()>2)return 0;        return 1;    }    void dfs(int x,int f){        D[x]=D[f]+1;        REP(i,0,E[x].size()-1){            int y=E[x][i];            if(y==f)continue;            dfs(y,x);        }     }    void solve(){        int mm=0,s;        REP(i,1,n)if(E[i].size()==1){s=i;break;}        dfs(s,0);        REP(i,1,m){            int a=D[Q[i].from],b=D[Q[i].to];            if(a>b)swap(a,b);            A[++mm]=a;            A[++mm]=b+1;            cnt[a]++;            sum[b+1]++;        }        sort(A+1,A+mm+1);        int len=unique(A+1,A+mm+1)-A-1;        int now=0;        LL ans=0;        REP(i,1,len){            now-=sum[A[i]];            if(cnt[A[i]]>0)ans+=1LL*now*cnt[A[i]]+1LL*cnt[A[i]]*(cnt[A[i]]-1)/2;            now+=cnt[A[i]];        }        cout<<ans<<endl;    }}p_list;int main(){//    freopen("tree.in","r",stdin);//    freopen("tree.out","w",stdout);    cin>>n>>m;    REP(i,1,n-1){        int a,b;        scanf("%d%d",&a,&b);        E[a].push_back(b);        E[b].push_back(a);      }    REP(i,1,m)scanf("%d%d",&Q[i].from,&Q[i].to);    if(n<=1000)p60.solve();    else if(p_list.check())p_list.solve();    else p100.solve();    return 0;}

小结:今天考得不错,but第1题并不是敲了一遍就对了,还对拍了很久的小数据(该证明的还是要证明,该贪心的还是要贪心),并且要多考虑数据的一些下界和上界(很容易边界炸!!!);对dp还要再敏感一些,树上的题目该水的分一定要先水,再看有没有链的(话说这几次链的数据几乎都是错的…链还是多想想,这档分与正解相比不会太难)。