Winter Training #1

来源:互联网 发布:f100禁止mac访问 编辑:程序博客网 时间:2024/05/25 20:01

A
http://codeforces.com/problemset/problem/229/A
题意:给100个长1e4的01串,问最少的移动次数,造出一列全是1的
做法:我是把所有1找出来,如果有一行没有1显然gg。然后因为循环,所以在前面和后面各补一个。然后枚举1列的位置,对每行二分取到最小值求和即可。
代码:

#include <bits/stdc++.h>using namespace std;char str[105][10500];int cnt[105];int rec[105][10500];int main(){    int n, m;    scanf("%d%d", &n, &m);    for(int i=1;i<=n;i++)scanf("%s", str[i]+1);    bool ok=true;    for(int i=1;i<=n;i++){        bool flag=false;        for(int j=1;j<=m;j++)if(str[i][j]=='1')flag=true;        if(!flag){            ok=false;            break;        }    }    if(!ok){        printf("-1\n");        return 0;    }    memset(cnt, 0, sizeof(cnt));    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++)if(str[i][j]=='1')rec[i][++cnt[i]]=j;        rec[i][0]=rec[i][cnt[i]]-m;        rec[i][cnt[i]+1]=rec[i][1]+m;    }    int M=105*10500;/*  for(int i=1;i<=n;i++){        for(int j=0;j<=cnt[i]+1;j++)printf("%d ", rec[i][j]);        printf("\n");    }*/    for(int i=1;i<=m;i++){        int tmp=0;        for(int j=1;j<=n;j++){            tmp+=min(i-*(upper_bound(rec[j], rec[j]+cnt[j]+2, i)-1), *(lower_bound(rec[j], rec[j]+cnt[j]+1, i))-i);        }        M=min(M, tmp);    }    printf("%d\n", M);}

B
http://codeforces.com/problemset/problem/229/B
题意:简单的最短路,附加条件是每个点有些时间不能走。
做法:在dij里改一下就行了。我一开始改了T了,后来发现因为会一直重复访问不能走的一段,加了一个d1数组防止重复访问就过了。
代码:

#include <bits/stdc++.h>using namespace std;struct edge{    int to, cost;};typedef pair<int, int> P;int n;vector<edge>g[105000];int d[105000];int d1[105000];vector<int>rec[105000];void dij(int s){    priority_queue<P, vector<P>, greater<P> >que;    for(int i=1;i<=n;i++)d[i]=d1[i]=1e9+1e8;    int st=0;    for(vector<int>::iterator it=rec[s].begin();it!=rec[s].end();it++){        if(*it<st)continue;        else if(*it==st)st++;        else break;    }    d[s]=d1[s]=st;    que.push(P(st, s));    while(!que.empty()){        P p=que.top();que.pop();        int v=p.second;        if(d[v]<p.first)continue;        for(vector<edge>::iterator it=g[v].begin();it!=g[v].end();it++){            edge e=*it;            if(d1[e.to]>d[v]+e.cost){                d1[e.to]=d[e.to]=d[v]+e.cost;                if(e.to==n)break;                for(vector<int>::iterator it1=rec[e.to].begin();it1!=rec[e.to].end();it1++){                    if(*it1<d[e.to])continue;                    else if(*it1==d[e.to])d[e.to]++;                    else break;                }                que.push(P(d[e.to], e.to));            }        }    }}int main(){    int m;    scanf("%d%d", &n, &m);    for(int i=1;i<=m;i++){        int a, b, c;        scanf("%d%d%d", &a, &b, &c);        edge t1, t2;        t1.to=b, t1.cost=c;        g[a].push_back(t1);        t2.to=a, t2.cost=c;        g[b].push_back(t2);    }    for(int i=1;i<=n;i++){        int num;        scanf("%d", &num);        for(int j=1;j<=num;j++)        {            int tmp;            scanf("%d", &tmp);            rec[i].push_back(tmp);        }    }    dij(1);    if(d[n]==1e9+1e8)printf("-1\n");    else printf("%d\n", d[n]);}

C
http://codeforces.com/contest/229/problem/C
题意:将一个1e6个点的完全图取1e6条边的子图,求这个子图和它的反图里一共有多少个三角形。
做法:考虑完全图的三角形数,是C(n,3);对于集合A、B,C(n,3)=由同1个集合的边构成的三角形+由A、B共同构成的三角形。所以我们只需要用C(n,3)减去三边分属于A、B集合的三角形即可。在一个n完全图中,一次拿掉一条边,与这条边有关的三角形有n-2个,减去n-2。但如果这条边的两端点已经有边,则减去n-2就多减了,作为补偿,要加上这两个点已有的边数,因为这些边和当前边确定的三角形已经在之前被减过了、
代码:

#include <bits/stdc++.h>using namespace std;typedef long long ll;ll rec[1050000];int main(){    memset(rec, 0, sizeof(rec));    ll n, m;    scanf("%I64d%I64d", &n, &m);    if(n<=2){        printf("0\n");        return 0;    }    ll ans=n*(n-1)*(n-2)/6;    memset(rec, 0, sizeof(rec));    for(int i=1;i<=m;i++){        int x, y;        scanf("%d%d", &x, &y);        ans-=(n-2-rec[x]-rec[y]);        rec[x]++;        rec[y]++;    }    printf("%I64d\n", ans);}

因为po主太菜了,D和E不会,待赛后填坑吧。

E
http://codeforces.com/contest/229/problem/E
题意:略
做法:看了xhr大爷的题解后发现,我特么题少看了个条件就是同名的价格两两不同,之后的事情就是正常的概率dp了。注意dp存的是前i种物品取了j个边界值的所有情况的成功率之和,所以最后还要除掉所有情况的种类数。
代码:

#include <bits/stdc++.h>using namespace std;int n, m;int pre[1050];int rec[1050][1050];int tot;int cnt[1050];int upp[1050];bool exs[1050];int tag;double c[1050][1050];double dp[1050][1050];int main(){    scanf("%d%d", &n, &m);    tot=0;    for(int i=1;i<=m;i++){        scanf("%d", &cnt[i]);        for(int j=1;j<=cnt[i];j++){            scanf("%d", &rec[i][j]);            pre[++tot]=rec[i][j];        }    }    sort(pre+1, pre+1+tot);    tag=pre[tot-n+1];    memset(exs, false, sizeof(exs));    memset(upp, 0, sizeof(upp));    for(int i=1;i<=m;i++){        for(int j=1;j<=cnt[i];j++){            if(rec[i][j]==tag)exs[i]=true;            else if(rec[i][j]>tag)upp[i]++;        }    }    for(int i=1;i<=1005;i++)        for(int j=0;j<=i;j++){            if(j==0||j==i)c[i][j]=1;            else c[i][j]=c[i-1][j-1]+c[i-1][j];        }    int eql=0;    int supp=0;    for(int i=1;i<=m;i++)if(exs[i])eql++;    for(int i=1;i<=m;i++)supp+=upp[i];    for(int i=0;i<=1005;i++)for(int j=0;j<=1005;j++)dp[i][j]=0;    dp[0][0]=1;    for(int i=1;i<=m;i++)        for(int j=0;j<=n-supp;j++)        {            if(exs[i]&&j){                dp[i][j]=dp[i-1][j]/c[cnt[i]][upp[i]]+dp[i-1][j-1]/c[cnt[i]][upp[i]+1];            }            else {                dp[i][j]=dp[i-1][j]/c[cnt[i]][upp[i]];            }        }    printf("%.11f\n", dp[m][n-supp]/c[eql][n-supp]);}
0 0