[考试] [NOIP模拟] [2017-11-01] 极其良(e)心的一次考试

极其良(e)心的一次考试

1.管道(pipe)

Description
  给你一个城市下水道网络图,你需要选出一些管道,使得在只使用这些管道的情况下,令整个网络联通,并且花费最小
  网络图可以看做是无向连通图,有n个节点和m条边,每条边连接 ui u i vi v i ,选择的花费是 wi w i
  不巧的是,由于某些原因,现在市政局要求选定某条特定的边管道,你的任务是求出对于某一条边,在选择这条管道的前提下的最小花费

Input
  第1行包含两个整数n,m,表示点数和边数
  第2~m+1行每行三个整数 ui u i vi v i wi w i ,表示有一条管道连接 ui u i vi v i ,费用为 wi w i

Output
  输出m行,每行一个整数,表示选择第i条管道的前提下的最小花费
  管道按输入的顺序编号为1~m

Sample Input
5 7
1 2 3
1 3 1
1 4 5
2 3 2
2 5 3
3 4 2
4 5 4

Sample Output
9
8
11
8
8
8
9

Hint
对于20%的数据,n<=1000,m<=2000
对于另外20%的数据,m<=n+10
对于100%的数据,2<=n<=100000,1<=m<=200000
保证初始图连通

棋盘(chessboard)

Description
  给你一个棋盘,上面有n*n个格子,一开始全部被涂上了黑色。你有一把魔术刷,可以将其中一些格子涂成白色。可惜的是,你不懂事的小妹妹把棋盘摔到了地上,导致其中一些格子摔坏了,不能被涂上白色
  我们定义一个染色方案的魔法值是它最大白色子正方形的边长,你的任务是计算出对于每一个魔法值,有多少种不同的染色方案可以得到它
  tu
  例如,N=3时,棋盘如J(a)所示,有两种染色方案可以得到2的魔法值,分别如J(b)和J(c)所示
  由于方案数可能很大,你只需要输出它对10^9+7取模后的值

Input
  第1行包含一个正整数n,表示棋盘的边长
  第2~n+1行,每行包含一个长度为n的字符串,只含有“o”和“*”,“o”表示一个完好的格子,“*”表示一个摔坏的格子

Output
  输出n+1行,每行包含一个整数,表示魔法值为i-1的方案数模10^9+7后的值

Sample Input 1
3
oo*
ooo
***

Sample Output 1
1
29
2
0

Sample Input 2
8
oooooooo
oooooooo
oooooooo
oooooooo
oooooooo
oooooooo
oooooooo
oooooooo

Sample Output 2
1
401415247
525424814
78647876
661184312
550223786
365317939
130046
1

Hint
对于10%的数据,n<=3
对于20%的数据,n<=4
对于30%的数据,n<=5
对于50%的数据,n<=6
对于70%的数据,n<=7
对于100%的数据,n<=8

3.颜色(color)

Description
  世界上有n种颜色,每种颜色有着一个美丽度
  现在你有一根分成n段的木棒,分别被涂上了颜色,可以将木棒看做长度为n的颜色序列。一段木棒的美丽度定义为出现的颜色的美丽度之和,如果一种颜色出现了多次,也只被计算一次
  现在你需要回答一些询问,每个询问形如 (liri) ( l i , r i ) ,意思是询问木棒上 [liri] [ l i , r i ] 这一段的美丽度
  由于世界线收束,有时候某段的颜色会被修改

Input
  第1行包含两个整数n和m,表示木棒的长度和操作个数
  第2行包含n个整数,表示每一段的初始颜色ci
  第3行包含n个整树,表示每种颜色的美丽度wi
  第4~m+3行,每行第1个整数kind
  若kind=1,后面跟两个整数p和c,表示将第p段的颜色改成c
  若kind=2,后面跟两个整数l和r,表示询问[li,ri]的美丽度

Output
对于每个kind=2的操作,输出一行一个整数,表示 [liri] [ l i , r i ] 的美丽度

Sample Input
3 3
1 2 3
1 2 3
2 1 3
1 1 2
2 1 3

Sample Output
6
5

Hint
对于10%的数据,n,m<=1000
对于另外10%的数据,保证所有2操作在1操作之后
对于另外20%的数据,保证wi=1
对于另外10%的数据,n,m<=30000
对于另外10%的数据,n,m<=50000
对于另外10%的数据,n,m<=70000
对于另外10%的数据,n,m<=80000
对于另外10%的数据,n,m<=90000
对于100%的数据,n,m<=100000

策略:

T1:看起来像是一个最小生成树?内含一个LCA?很可做
预计分:100
实际得分:100

T2:数学?搜索?算了看都不想看
预计分:0
实际得分:你懂的

T3:树状数组么?没学啊(吐血~),看看能不能线段树来一波,算了太难了还是暴力吧
预计分:10
实际得分:30

T1:
给你n个点,m条边,包含第i条边的最小生成树的大小
可以证明,包含第i条边的最小生成树的其他边一定是属于原最小生成树的
那么第i条边连接的 ui u i vi v i 的路径上的边都是可以删去的(当然选最大的边删去),树上路径当然LCA(或树剖),我们在倍增求LCA的时候维护一下最大边即可。

#include <bits/stdc++.h>
using namespace std;
struct Edge {
    int u;
    int v;
    int c;
    int point;
}edge[400010];
int fa[100010],num[100010],n,m;
int head[100010],to[200010],c[200010],net[200010],tot=0;
int f[100010][20],cost[100010][20],maxdeep=0,top,deep[100010];
long long sum=0;
bool use[200010];
int read() {
    int ans=0,flag=1;
    char ch=getchar();
    while( (ch>'9' || ch<'0') && ch!='-' ) ch=getchar();
    if(ch=='-') flag=-1,ch=getchar();
    while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();
    return ans*flag;
}
bool cmp(Edge a,Edge b) {return a.c<b.c;}
int find(int x) {
    if(x!=fa[x]) 
        fa[x]=find(fa[x]);
    return fa[x];
}
void merge(int fx,int fy) {
    if(num[fx]>num[fy]) swap(fx,fy);
    fa[fx]=fy;
    num[fy]+=num[fx];
    num[fx]=0;
    return ;
}
void addedge(int u,int v,int w) {
    to[++tot]=v;
    c[tot]=w;
    net[tot]=head[u];
    head[u]=tot;
    return ;
}
void work() {
    int fx,fy;
    for(int i=1;i<=n;i++) fa[i]=i,num[i]=1;
    for(int i=m+1;i<=m*2;i++) {
        fx=find(edge[i].u);
        fy=find(edge[i].v);
        if(fx!=fy) {
            merge(fx,fy);
            use[edge[i].point]=1;
            addedge(edge[i].u,edge[i].v,edge[i].c);
            addedge(edge[i].v,edge[i].u,edge[i].c);
            sum+=edge[i].c;
        }
    }
    return ;
}
void build(int x) {
    for(int i=head[x];i;i=net[i]) {
        if(to[i]==f[x][0]) continue;
        f[to[i]][0]=x;
        cost[to[i]][0]=c[i];
        deep[to[i]]=deep[x]+1;
        maxdeep=max(maxdeep,deep[to[i]]);
        build(to[i]);
    }
    return ;
}
void prepare() {
    for(top=0;maxdeep>(1<<top);top++);
    for(int k=1;k<=top;k++) {
        for(int i=1;i<=n;i++) {
            cost[i][k]=max(cost[i][k-1],cost[f[i][k-1]][k-1]);
            f[i][k]=f[f[i][k-1]][k-1];
        }
    }
    return ;
}
int lca(int x,int y) {
    int maxans=0;
    if(deep[x]<deep[y])
        swap(x,y);
    for(int i=top;i>=0;i--)
        if(deep[f[x][i]]>=deep[y]) {
            maxans=max(maxans,cost[x][i]);
            x=f[x][i];
        }
    if(x==y) return maxans;
    for(int i=top;i>=0;i--) {
        if(f[x][i]!=f[y][i]) {
            maxans=max(maxans,cost[x][i]);
            maxans=max(maxans,cost[y][i]);
            x=f[x][i];
            y=f[y][i];
        }
    }
    maxans=max(maxans,cost[x][0]);
    maxans=max(maxans,cost[y][0]);
    return maxans;
}
int main() {
    freopen("pipe.in","r",stdin);
    freopen("pipe.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=m;i++) {
        edge[i].u=read();
        edge[i].v=read();
        edge[i].c=read();
        edge[i+m].u=edge[i].u;
        edge[i+m].v=edge[i].v;
        edge[i+m].c=edge[i].c;
        edge[i].point=edge[i+m].point=i;
    }
    sort(edge+1+m,edge+m+1+m,cmp);
    work();
    deep[1]=1;
    build(1);
    prepare();
    for(int i=1;i<=m;i++) {
        if(use[i]) printf("%lld\n",sum);
        else {
            printf("%lld\n",sum-(long long)lca(edge[i].u,edge[i].v)+edge[i].c);
        }
    }
    return 0;
}

T2:
听说这题是动态规划?我居然信了…
暂时还没有看懂QAQ

T3:
这是这套试题中最玄学的一题
原本10分的暴力莫名变成了30分?
打了莫队+暴力还没有纯暴力分高?
好吧,我服
题解没有看懂,但是发现了一个神奇的算法——莫队(还没看懂)
又发现了一个神奇的算法——分块
可以解决这个题目部分分( wi w i =1)
用pre[i]记录前一个和i相同颜色的段的所在位置
询问l到r时,如果pre[i]不在区间[l,r]内(即 pre[i]<l p r e [ i ] < l )说明在l到i这一段没用和i颜色相同的段,则ans++
每一块内按pre[i]排序,然后二分查找即可,ans=find(l,r)-l

总结
  这次考试状况连连,话说找不到机子考试是什么鬼~键盘比较反人类,打起来黏黏的,不舒服。大家考的好像都不怎么样(abs请无视),但是自我感觉还是可以的,心态没有爆炸,考出了自己的水平(就是一个字——稳)。加油吧,向NOIP冲刺!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值