2017百度之星初赛B场总结

(A场因为不可抗力因素(?)没能参加,B场还好算是磕磕碰碰地吃着低保过去了,真的菜呀)

  • Chess
    Problem Description
    車是中国象棋中的一种棋子,它能攻击同一行或同一列中没有其他棋子阻隔的棋子。一天,小度在棋盘上摆起了许多車……他想知道,在一共N×M个点的矩形棋盘中摆最多个数的車使其互不攻击的方案数。他经过思考,得出了答案。但他仍不满足,想增加一个条件:对于任何一个車A,如果有其他一个車B在它的上方(車B行号小于車A),那么車A必须在車B的右边(車A列号大于車B)。
    现在要问问你,满足要求的方案数是多少。
    Input
    第一行一个正整数T,表示数据组数。
    对于每组数据:一行,两个正整数N和M(N<=1000,M<=1000)。
    Output
    对于每组数据输出一行,代表方案数模1000000007(1e9+7)。

可以说还是比较一目了然的签到题,由于这些点的横纵坐标都必须严格递增,那么我们最多能取到的点就是 min(n,m) 个;方案数就相当于是在 max(n,m) 中选 min(n,m) 个的方案数,那么答案就是 C(max(n,m),min(n,m)) 了。
留意数据范围,用杨辉三角预处理答案就可以了(先写lucas定理再写拓欧的我大概是失了智)。

  • Factory
    Problem Description
    我们将A省简化为由N个城市组成,某些城市之间存在双向道路,而且A省的交通有一个特点就是任意两个城市之间都能通过道路相互到达,且在不重复经过城市的情况下任意两个城市之间的到达方案都是唯一的。聪明的你一定已经发现,这些城市构成了树这样一个结构。
    现在百度陆续开了许许多多的子公司。每家子公司又会在各城市中不断兴建属于该子公司的办公室。
    由于各个子公司之间经常有资源的流动,所以公司员工常常想知道,两家子公司间的最小距离。 我们可以把子公司看成一个由办公室组成的集合。那么两个子公司A和B的最小距离定义为min(dist(x,y))(x∈A,y∈B)。其中dist(x,y)表示两个办公室之间的最短路径长度。
    现在共有Q个询问,每次询问分别在两个子公司间的最小距离。
    Input
    第一行一个正整数T,表示数据组数。
    对于每组数据:
    第一行两个正整数N和M。城市编号为1至N,子公司编号为1至M。
    接下来N-1行给定所有道路的两端城市编号和道路长度。
    接下来M行,依次按编号顺序给出各子公司办公室所在位置,每行第一个整数G,表示办公室数,接下来G个数为办公室所在位置。
    接下来一个整数Q,表示询问数。
    接下来Q行,每行两个正整数a,b(a不等于b),表示询问的两个子公司。
    【数据范围】
    0<=边权<=100
    1<=N,M,Q,工厂总数<=100000
    Output
    对于每个询问,输出一行,表示答案。

这题大概是数据没出好?据说 Tn2logn 的暴力也能过233
正解没什么头绪,留坑待填(据jiangshibiao大神说是根据集合大小分开处理orz)

  • 路径计数
    Problem Description
    一个包含四个点的完全图,可以在任意节点出发,可以在任意节点结束,给出每个点被经过的次数,求有多少种合法的遍历序列。如果两个序列至少有一位是不同的,则认为它们不相同。
    样例: 1 2 1 0
    ABCB BABC BACB BCAB BCBA CBAB
    Input
    多组数据。 对于每一组数据: 第一行四个数,分别表示4个点被经过的次数(每个数小于等于1000,经过次数可以为0)
    Output
    一个表示答案,对998244353取模.

这道题的题意实际上是问我们一个含有一定数量ABCD且相邻字符不相等的序列有多少个。一个 n4 的TLE解法很快就能想出来了:用每个字符已经出现的次数和最后一个字符表示状态,然后再瞎dp一番。
至于正解,我们其实可以用一种类似于小朋友们学组合数学时用的“插板”的理解方式来理解这个过程。我们每一次把所有的某种字符摆放到原有的字符的中间,那么这个过程中,就会有一些原本的连续相同字符段被分隔开,有一些新的连续相同字符段产生。由于每次放置一种字符,所统计的每种方案字符相对位置有所不同,所以不会出现重复统计的情况。可以用 f[i][j] 表示已经放了i种字符,还存在j个连续相同字符段的方案数, f[i] 数组和 f[i1] 之间存在递推关系(好像有点麻烦先挖个坑)。
(时间复杂度大概是 O(n2) ?)(感谢dhr小朋友)

  • 打怪兽2
    我甚至没看懂题面。。。没法口胡呀这XD
  • 度度熊的交易计划
    Problem Description
    度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题:
    喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组由成的地区。
    由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但是最多生产b[i]个。
    同样的,由于每个片区的购买能力的区别,第i个片区也能够以c[i]的价格出售最多d[i]个物品。
    由于这些因素,度度熊觉得只有合理的调动物品,才能获得最大的利益。
    据测算,每一个商品运输1公里,将会花费1元。
    那么喵哈哈村最多能够实现多少盈利呢?
    Input
    本题包含若干组测试数据。 每组测试数据包含: 第一行两个整数n,m表示喵哈哈村由n个片区、m条街道。 接下来n行,每行四个整数a[i],b[i],c[i],d[i]表示的第i个地区,能够以a[i]的价格生产,最多生产b[i]个,以c[i]的价格出售,最多出售d[i]个。 接下来m行,每行三个整数,u[i],v[i],k[i],表示该条公路连接u[i],v[i]两个片区,距离为k[i]
    可能存在重边,也可能存在自环。
    满足: 1<=n<=500, 1<=m<=1000, 1<=a[i],b[i],c[i],d[i],k[i]<=1000, 1<=u[i],v[i]<=n
    Output
    输出最多能赚多少钱。

是一道相当友好的网络流裸题了。S向每个片区连费用为 a[i] 容量为 b[i] 的边,片区间连费用为0容量为无穷大的边,每个片区向T连费用为 c[i] 容量为 d[i] 的边。图显然不会出现负环,直接跑一个spfa的最小费用流即可(增广到费用不小于零的路径就停止)。

#include
#include
#include
#include
#define inf 0x7f7f7f7f
using namespace std;
int d[1010],dis[510][510],n,m,a[1010],to[2000010],nxt[2000010],cap[2000010],path[1010],cnt,S,T;
bool inq[1010],boo[510][510];
void addedge(int u,int v,int c){
    to[++cnt]=v;nxt[cnt]=a[u];cap[cnt]=c;a[u]=cnt;
}
int SPFA(){
    queue<int> q;
    memset(d,0x7f,sizeof(d));
    memset(inq,0,sizeof(inq));
    memset(path,0,sizeof(path));
    q.push(S);
    d[S]=0;inq[S]=1;
    while (!q.empty()){
        int x=q.front();q.pop();inq[x]=0;
        for (int i=a[x];i;i=nxt[i]){
            int y=to[i];
            int cost=dis[x][y];
            if (i%2) cost=-cost;
            if (cap[i]>0&&d[x]+costy]){
                d[y]=d[x]+cost;
                path[y]=i;
                if (inq[y])continue;
                q.push(y);
                inq[y]=1;
            }
        }
    }
    return d[T];
}
int flow(){
    int p=T,f=inf;
    while (p!=S){
        f=min(f,cap[path[p]]);
        p=to[path[p]^1];
    }
    p=T;
    while (p!=S){
        cap[path[p]]-=f;
        cap[path[p]^1]+=f;
        p=to[path[p]^1];
    }
    return f;
}
void solve(){
    S=0;T=n+1;cnt=1;
    memset(a,0,sizeof(a));
    memset(nxt,0,sizeof(nxt));
    memset(dis,0x7f,sizeof(dis));
    memset(boo,0,sizeof(boo));
    for (int i=1;i<=n;i++){
        int A,B,C,D;
        scanf("%d%d%d%d",&A,&B,&C,&D);
        dis[i][T]=dis[T][i]=A;
        dis[S][i]=dis[i][S]=-C;
        addedge(i,T,B);
        addedge(T,i,0);
        addedge(S,i,D);
        addedge(i,S,0);
    }
    for (int i=1;i<=m;i++){
        int u,v,k;
        scanf("%d%d%d",&u,&v,&k);
        if (u==v) continue;
        if (!boo[u][v]) {
            boo[u][v]=boo[v][u]=1;
            addedge(u,v,inf);
            addedge(v,u,0);
            addedge(v,u,inf);
            addedge(u,v,0);
        }
        dis[u][v]=min(dis[u][v],k);
        dis[v][u]=dis[u][v];
    }
    int ret=0,dist;
    while (dist=SPFA()) {
        if (dist>=0) break;
        ret-=flow()*dist;
    }n",ret); } int main(){ while(scanf("%d%d",&n,&m)!=EOF) solve(); }

丑陋的代码。

  • 度度熊的交易计划
    Problem Description
    度度熊喜欢着喵哈哈村的大明星——星星小姐。
    为什么度度熊会喜欢星星小姐呢?
    首先星星小姐笑起来非常动人,其次星星小姐唱歌也非常好听。
    但这都不是最重要的,最重要的是,星星小姐拍的一手好代码!
    于是度度熊关注了星星小姐的贴吧。
    一开始度度熊决定每天都在星星小姐的贴吧里面签到。
    是度度熊是一个非常健忘的孩子,总有那么几天,度度熊忘记签到,于是就断掉了他的连续签到。
    不过度度熊并不是非常悲伤,因为他有m张补签卡,每一张补签卡可以使得某一忘签到的天,变成签到的状态。
    那么问题来了,在使用最多m张补签卡的情况下,度度熊最多连续签到多少天呢?
    Input
    本题包含若干组测试数据。
    第一行两个整数n,m,表示有n个区间,这n个区间内的天数,度度熊都签到了;m表示m张补签卡。
    接下来n行,每行两个整数(l[i],r[i]),表示度度熊从第l[i]天到第r[i]天,都进行了签到操作。
    数据范围:
    1<=n<=100000
    0<=m<=1000000000 0<=l[i]<=r[i]<=1000000000
    注意,区间可能存在交叉的情况。
    Output
    输出度度熊最多连续签到多少天。

简单签到题,先预处理出不重叠的区间,再维护连续的一段看看能不能被m天相连,最后处理多余的补签卡即可。

实话说这场比赛收获不大……但为了有个好的新开始还是决定写一篇口胡总结,毕竟得打回些状态啊QAQ。

你可能感兴趣的:(百度之星,单场总结)