2017.10.10离线赛总结

来源:互联网 发布:博雅软件股份有限公司 编辑:程序博客网 时间:2024/06/05 08:50

str —2992

思路:染色,将每个连通的’.’依依标记id和对应的个数sum。那么答案就是每个’*’的四个方向的连通块sum和。However,每次memset mark[][](判重)是O(n^2)的,所以会超时,也就是只需要for过来…

subpal —2993

思路:区间dp,和完美队形一模一样,但这是求可行的方案数,那么就前缀和再维护一下dp即可。(然而今天就炸在此题,最后无聊把代码放结构体里,结果int main里外都打了int n…)

#include<bits/stdc++.h>#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 N 2005#define INF 0x3f3f3f3f#define LL long long#define P 100007// LL mod using namespace std;int n,m;char s[N];int ans,sum;int dp[N];void Add(int &a,int b){a=(a+b)%P;}struct P100{    void solve(){        REP(i,1,n){            int cnt=0;            DREP(j,n,i){                Add(cnt,dp[j]);                if(s[i]==s[j]){                    dp[j]=cnt+1;                    if(dp[j]>P) dp[j]-=P;                }            }        }        REP(i,1,n) Add(ans,dp[i]);        cout<<ans<<endl;    }}p100;int main(){    scanf("%s",s+1);    n=strlen(s+1);    p100.solve();     return 0;} 

tree —2948

思路:与2968神似,也是询问和维护最值,离线来做。那么先求最小生成树,并mark有用的边,最后倍增一样的套路(当然也可以一个一个up上去,考试没有时间写倍增了…)

#include<bits/stdc++.h>#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 N 50005#define M 200005#define INF 0x3f3f3f3f#define LL long long#define P 100007// LL mod 调试 文件名 using namespace std;int n,m;bool mark[M];int fa[N],D[N];int Id[M],res[M];struct edge{    int from,to,cost,id;    bool operator<(const edge &a)const{        return cost<a.cost;    }}es[M];struct node{    int to,cost,id;};vector<node>E[N]; int Find(int x){return fa[x]==x?x:fa[x]=Find(fa[x]);}struct P50{    bool check(){        REP(i,2,n)if(fa[i]!=fa[i-1])return 0;        return 1;    }    int Kruskal(int w){        int res=0;        REP(i,1,n)fa[i]=i;        REP(i,1,m){            if(es[i].id==w)continue;            int x=Find(es[i].from),y=Find(es[i].to);            if(x==y)continue;            fa[x]=y;            res+=es[i].cost;         }        REP(i,1,n)fa[i]=Find(i);        if(!check())return -1;        return res;    }    void solve(){        REP(i,1,m){            int ans=Kruskal(i);            printf("%d\n",ans);        }    }}p50;void chkmin(int &x,int y){if(!x || x>y)x=y;} struct P100{    int sum,ans;    struct Tree{        int fa,id;    }tree[N];    void dfs(int x,int f,int dep){        REP(i,0,E[x].size()-1){            node y=E[x][i];            if(y.to==f)continue;            D[y.to]=dep+1;            tree[y.to]=(Tree){x,y.id};            dfs(y.to,x,dep+1);         }    }    void Kruskal(){        REP(i,1,n)fa[i]=i;        REP(i,1,m){            int x=Find(es[i].from),y=Find(es[i].to);            if(x==y)continue;            fa[x]=y;            ans+=es[i].cost;            E[es[i].from].push_back((node){es[i].to,es[i].cost,es[i].id});            E[es[i].to].push_back((node){es[i].from,es[i].cost,es[i].id});            mark[es[i].id]=1;            sum++;        }    }    void Up(int &x,int c){        chkmin(res[tree[x].id],c);        x=tree[x].fa;    }    void work(int a,int b,int c){        while(D[a]>D[b])Up(a,c);        while(D[a]<D[b])Up(b,c);        while(a!=b)Up(a,c),Up(b,c);     }    void solve(){        sum=ans=0;        Kruskal();        if(sum<n-1){            REP(i,1,m)puts("-1");            exit(0);        }        dfs(1,0,0);        REP(i,1,m){            if(mark[es[i].id])continue;            work(es[i].from,es[i].to,es[i].cost);        }        REP(i,1,m){            if(!mark[i])printf("%d\n",ans);            else if(!res[i])puts("-1");            else printf("%d\n",ans+res[i]-es[Id[i]].cost);        }    }}p100; int main(){    scanf("%d%d",&n,&m);    REP(i,1,n)fa[i]=i;    REP(i,1,m)scanf("%d%d%d",&es[i].from,&es[i].to,&es[i].cost),es[i].id=i;    sort(es+1,es+1+m);    REP(i,1,m)Id[es[i].id]=i;    if(m<=3000)p50.solve();    else p100.solve(); //  p100.solve();    return 0;}

小结:由于这次第2题又犯了低级错误,而且还是考试最后几分钟改错的,可见最后5分钟还是解放双手,好好检查…

原创粉丝点击