2017.11.04离线赛总结

foreat ——3805

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

robot ——3806

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

#include
#include
#include
#include
#include
#include
#include
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 20

int 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;iint 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<1<int base[1<void Init(){
        mcl(dp,INF);
        REP(i,0,K-1)base[1<0][i]=dp[1<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<1){
            REP(j,0,K-1){
                if((i&(1<continue;
                int x=i&(-i);
                sum[i][j]=sum[i-x][j]+last[j][base[x]];
            }
        } 
        REP(i,0,(1<1){
            REP(j,0,K-1){
                if(i&(1<continue;
                dp[i|(1<1<cout<1<1]<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
#include
#include
#include
#include
#include
#include
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 1005

int 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]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]]return D[a]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<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]]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<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<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还要再敏感一些,树上的题目该水的分一定要先水,再看有没有链的(话说这几次链的数据几乎都是错的…链还是多想想,这档分与正解相比不会太难)。

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