tEST 3 for NOIP

来源:互联网 发布:网络试衣间 编辑:程序博客网 时间:2024/05/17 22:28

头更大

这个9月完就要去集训搞NOIP了。。。

9月30天也就3次测试。。。为防万一我还是每次测试玩都写个总结。。


第三题强势暴力,第二题浪了。
第一题。。。。。。

mmp读入优化有毒!!!
mmp读入优化有毒!!!
mmp读入优化有毒!!!

跳高

题目背景
SOURCE:NOIP2015-HN-CJZX

题目描述
r64 喜欢跳高。但是他的技术并不好,所以他想好好练习一下。

练习场上有一个个高度不一定一样的平台,如图所示。最底下的是地板,高度为 0 。有 n 个平台,第 i 个平台的高度为 hi (hi≥0)。作为一名跳高爱好者,r64 希望跳到尽可能高的平台。

但是 r64 技术不好,他的最大跳跃高度是 Δh 。也就是说,如果 r64 当前高度为 h1 ,某个平台的高度为 h2 (h2≥h1 ),那么 r64 能跳到这个平台,当且仅当 h2≤h1+Δh 。之后,r64 的高度变成 h2 。

除此之外,r64 规定他自己不能多次跳上同一个平台。

r64 想知道,他最多能跳多高。并且,在跳得尽量高的前提下,他最多经过多少个平台,以及最少经过多少个平台。

输入格式
输入第一行有两个正整数 n 和 Δh ,分别表示平台个数和 r64 的最大跳跃高度。
接下来一行有 n 个非负整数 h1,h2,…,hn,表示每个平台的高度。

输出格式
输出只包括一行三个整数 maxh,maxjump,minjump,分别表示 r64 能跳的最大高度、他跳到高度 maxh 所经过的平台数量的最大值与最小值。

样例数据 1
输入  [复制]

5 2
1 2 3 5 3
输出

5 5 3
样例数据 2
输入  [复制]

9 1
1 2 3 4 6 7 8 9 10
输出

4 4 4
备注
【样例1说明】
经过平台数量为 5 的一种跳法是:0→1→2→3→3→5。
经过平台数量为 3 的一种跳法是:0→2→3→5。当然,0→1→3→5也是允许的。

【数据说明】
一共 20 个测试点,每个测试点的特征如下表所示。
这里写图片描述

。。。考试时一群人死在没有加读入优化上。。。但更不能理解的是曾老电脑的cin比scanf快了好几倍?????
用scar_lyw的话来说,鬼畜了。

MY/STD.CPP

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstdlib>#include<string>#include<cstring>#include<ctime>using namespace std;int n,m;int a[1000500],f[1000500];int maxh=0,maxj=0,minj=0;int main(){//  freopen("jump.in","r",stdin);//  freopen("jump.out","w",stdout);     ios::sync_with_stdio(false);    cin.tie(NULL);    cin >> n >> m;    for(int i=1;i<=n;i++)        cin >> a[i];    sort(a+1,a+n+1);    for(int i=1;i<=n;i++)    {        if(a[i]-a[i-1]>m)break;        else{            maxh = a[i];            maxj += 1;            if(a[i]!=a[i-1])              f[i] = a[i];        }    }    memset(a,127,sizeof(a));    a[0] = 0;    int head=0,tail=0;    while(f[tail]!=maxh)    {        tail++;        while(f[head]+m<f[tail])head++;        a[tail]=min(a[tail],a[head]+1);    }    minj = 999999999;    while(f[head]+m<f[tail])head++;        minj = min(minj,a[head]+1);    if(maxh==0)minj=0;    cout<<maxh<<" "<<maxj<<" "<<minj<<endl;}

证明

题目背景
SOURCE:NOIP2015-HN-CJZX

题目描述
H 教授是一位德高望重的教授,也是计算机科学界的权威。他对问题总有独特而深刻的见解,治学严谨,是学术界的带头人。

在一次科学家大会上,H 教授在黑板上写下了 n 个式子 x1,x2,…,xn ,并向参加会议的所有科学家证明了:如果 x1=x2=…=xn,那么可以证明 P=NP 。可是,毕竟人无完人,H 教授对其中的任意两个式子是否相等都说不清。他把这个问题抛给了全世界的科学家们。

令人激动的是,没过多久,H 教授就收到了数学家们发来的 m 封 email ,第 i 封 email 写到,发信人已经证明了 ∀li≤a< ri,xa=xa+1,即 xli,x(li)+1,…,xri 两两相等。但是,这些证明是有版权的,如果 H 教授需要使用这些证明,那么需要向提供证明的人支付 ci 元稿费。

H 教授希望通过这些信息证明出 P=NP 。但是,H 教授最近手头拮据,所以希望支付最小的费用。

输入格式
输入的第一行是两个整数 n,m。
接下来 m 行,每行三个整数 li,ri,ci (1≤li≤ri≤n),代表第 i 位数学家的证明及其稿费。

输出格式
输出只包含一个整数,表示 H 教授至少要支付多少元稿费,才能证明出 P=NP。如果根据现有条件无法证明 P=NP ,请输出-1。

样例数据 1
输入  [复制]

9 3
1 3 101010
4 6 98889
7 9 76543
输出

-1
样例数据 2
输入  [复制]

9 7
1 5 3
3 6 8
5 8 4
4 7 6
2 3 7
7 9 2
6 7 5
输出

9
备注
【样例1说明】
就算把所有的数学家都叫上,仍然证明不了 x3=x4 和 x6=x7。

【样例2说明】
第一位数学家可以证明 x1=x2=x3=x4=x5。
第三位数学家可以证明 x5=x6=x7=x8。
第六位数学家可以证明 x7=x8=x9。
这三位数学家是足够的,并且只需 9 元稿费。可以证明没有更优的方案。

【数据说明】
所有测试点的数据范围如下表所示。
这里写图片描述

一开始觉得标答无望就乱打了个有向图套Dijkstra(边多)后来发现还差点打成标答。。。但是建边的时候瓜了。
额我具体怎么挂的自己看吧。

MY.CPP

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstdlib>#include<string>#include<cstring>#include<ctime>#include<queue>using namespace std;const int kkk=100055;int n,m;struct nde{    int l,r,c;}s[kkk];bool comp(const nde &a,const nde &b){if(a.l==b.l)return a.r<b.r;return a.l<b.l;}struct node{    int u,v,val,next;}side[6*kkk];int cnt=0,first[kkk];void addedge(int u,int v,int val){    cnt += 1;    side[cnt].u = u;    side[cnt].v = v;    side[cnt].val = val;    side[cnt].next = first[u];    first[u] = cnt;}bool visit[kkk];long long dis[kkk];long long dij(int s,int t){    memset(dis,126,sizeof(dis));    priority_queue< pair<long long,int> >que;    que.push(make_pair(0,s));    dis[s] = 0;    long long gud = dis[t];    while(!que.empty())    {        pair<int,int> k = que.top();        que.pop();        visit[k.second] =true;        for(int j=first[k.second];j;j=side[j].next)        {            int v = side[j].v;            if(!visit[v] && dis[v]>dis[k.second]+side[j].val)            {                dis[v] = dis[k.second]+(long long)side[j].val;                que.push(make_pair(-dis[v],v));            }        }    }    if(dis[t]==gud)return -1;    return dis[t];}int main(){//  freopen("proof.in","r",stdin);//  freopen("proof.out","w",stdout);        cin>>n>>m;    for(int i=1;i<=m;i++)    cin>>s[i].l>>s[i].r>>s[i].c;    sort(s+1,s+m+1,comp);    int head=1,tail=1;    addedge(s[tail].l,s[tail].r,s[tail].c);     while(tail!=m)    {        tail++;   addedge(s[tail].l,s[tail].r,s[tail].c);           while(s[head].r<s[tail].l)head++;        for(int i=head;i<tail;i++)            addedge(s[i].l,s[tail].l,s[i].c);       }    cout << dij(1,n) << endl;}

哦对了标答还要记得套个离散化还有把数组开到1e6不然会卡四个点。

STD.CPP

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstdlib>#include<string>#include<cstring>#include<ctime>#include<queue>using namespace std;const int kkk=1000055;int n,m;struct nde{    int l,r;    long long c;}s[kkk];bool comp(const nde &a,const nde &b){if(a.l==b.l)return a.r<b.r;return a.l<b.l;}struct node{    int u,v,val,next;}side[6*kkk];int cnt=0,first[kkk];void addedge(int u,int v,int val){    cnt += 1;    side[cnt].u = u;    side[cnt].v = v;    side[cnt].val = val;    side[cnt].next = first[u];    first[u] = cnt;}bool visit[kkk];long long dis[kkk];long long dij(int s,int t){    memset(dis,126,sizeof(dis));    priority_queue< pair<long long,int> >que;    que.push(make_pair(0,s));    dis[s] = 0;    long long gud = dis[t];    while(!que.empty())    {        pair<int,int> k = que.top();        que.pop();        visit[k.second] =true;        for(int j=first[k.second];j;j=side[j].next)        {            int v = side[j].v;            if(!visit[v] && dis[v]>dis[k.second]+side[j].val)            {                dis[v] = dis[k.second]+(long long)side[j].val;                que.push(make_pair(-dis[v],v));            }        }    }    if(dis[t]==gud)return -1;    return dis[t];}int num[2*kkk],tot=0;int main(){//  freopen("proof.in","r",stdin);//  freopen("proof.out","w",stdout);    cin>>n>>m;    for(int i=1;i<=m;i++)    {        cin>>s[i].l>>s[i].r>>s[i].c;            num[++tot]=s[i].l;num[++tot]=s[i].r;    }    num[++tot]=1;   num[++tot]=n;    sort(num+1,num+tot+1);    n = unique(num+1,num+tot+1)-num-1;    tot = n;    for(int i=1;i<=m;i++)    {        s[i].l=lower_bound(num+1,num+tot+1,s[i].l)-num;        s[i].r=lower_bound(num+1,num+tot+1,s[i].r)-num;        addedge(s[i].l,s[i].r,s[i].c);      }    for(int i=2;i<=n;i++)        addedge(i,i-1,0);    cout << dij(1,n) << endl;}

题目背景
SOURCE:NOIP2015-HN-CJZX

题目描述
树(tree)是指由 n 个点,n-1 条边构成的连通无向图。如果有一棵树,它的每一条边 (u,v) 都有一个权值 lu,v ,我们把这样的树称作带权树(weighted tree)。

我们知道对于树上的任意两个点,他们之间的路径是唯一的。对于两个点 u,v 来说,我们可以算出 u 与 v 之间的路径上所有边权之和,将其称作 u 与 v 之间路径的长度,记作 d(u,v)。

你的任务是计算:

输入格式
输入第一行为一个正整数 n 。
接下来 n-1 行,每行三个非负整数 x,y,w,表示点 x 与点 y 之间有一条权值为 w 的一条边。
保证输入的图是一棵树。

输出格式
输出仅包含一行一个数,即答案。因为结果可能很大,请将答案模 100 000 007 输出。

样例数据 1
输入  [复制]

4
1 2 4
1 3 4
1 4 4
输出

72
样例数据 2
输入  [复制]

10
1 2 1320321
2 3 4687651
3 4 1321357
4 5 6651332
5 6 5746513
6 7 5674687
7 8 7451216
8 9 7789965
9 10 8765134
输出

28244404
备注
【样例1说明】
d(1,2)+d(1,3)+d(1,4)=4+4+4=12
d(2,1)+d(2,3)+d(2,4)=4+8+8=20
d(3,1)+d(3,2)+d(3,4)=4+8+8=20
d(4,1)+d(4,2)+d(4,3)=4+8+8=20
所以答案为:12+20+20+20=72。

【数据范围】
共 20 个测试点,其数据特征如下表所示。
这里写图片描述对所有数据,有 1≤n≤3×105,0≤w<100 000 007。数据有一定梯度。

只能说自己考试时脑抽的吓人。正解很显然枚举每一条边,把边左右两边的点的个数和边权值乘起来就行了。
然而当我想到这一步的时候。。。我。竟。然。不。知。道。怎。么。求。一。条。边。两。边。的。点。的。个。数。了。。。。。然后打了个LCA的超级大暴搜。。。
后来看了一眼题解才发现一遍DFS完事。。。。。。

MY.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<algorithm>#include<string>#include<cstring>#include<queue>using namespace std;int n,m,x,y,u,v,val;struct node{    int u,v,val,next;}side[600010];int cnt=0,first[300010];void addedge(int u,int v,int val){    cnt += 1;    side[cnt].u = u;    side[cnt].v = v;    side[cnt].val = val;    side[cnt].next = first[u];    first[u] = cnt;}bool visit[300010];int dep[300010];long long dis[300010];int f[300010][20];void dfs(int root){    visit[root] = true;    for(int i=first[root];i;i=side[i].next)    {      int u = side[i].u;    int v = side[i].v;      if(!visit[v])      {        f[v][0] = u;        dep[v] = dep[u] + 1;        dis[v] = dis[u] + (long long)side[i].val;        dfs(v);      }    }}#define maxx 300005void initi(int root){    memset(dep,0,sizeof(dep));    dis[root] = 0;    dep[root] = 0;    dfs(root);    for(int i=1;i<=18;i++)      for(int j=1;j<=maxx;j++)        if(f[j][i-1])             f[j][i] = f[f[j][i-1]][i-1];}int lca(int x,int y){    if(dep[x]<dep[y]){int k=x;x=y;y=k;}    int foot = dep[x] - dep[y];    for(int i=18;i>=0;i--)      if(foot>=(1<<i))  foot -= (1<<i),x=f[x][i];    if(x==y)    return x;    for(int i=18;i>=0;i--)      if(f[x][i]!=f[y][i])  x=f[x][i],y=f[y][i];    return f[x][0];}int main(){//  freopen("tree.in","r",stdin);//  freopen("tree.out","w",stdout);     cin >> n ;    for(int i=1;i<n;i++)    {        cin >> u >> v >> val;        addedge(u,v,val);        addedge(v,u,val);    }    initi(1);    long long ans = 0;    for(int i=1;i<n;i++)      for(int j=i+1;j<=n;j++)      {        ans += 2*(dis[i]+dis[j]-2*dis[lca(i,j)]);        ans %= 100000007;      }    cout << ans << endl;}

STD.CPP

#include<algorithm>#include<iostream>#include<iomanip>#include<cstring>#include<cstdlib>#include<cctype>#include<string>#include<cstdio>#include<cmath>#include<ctime>#include<queue>#include<set>#include<map>using namespace std;const int kkk=300005;const int nod=100000007;long long n,ans,son[kkk],fa[kkk];long long cnt,first[kkk];struct node{    int u,v,next;    long long val;}side[2*kkk];inline long long read(){    long long i=0;  char ch;    ch=getchar();    while(ch>'9'||ch<'0')ch=getchar();    while(ch<='9'&&ch>='0')    {        i=(i<<3)+(i<<1)+ch-'0';        ch=getchar();    }    return i;}inline void add(int x,int y,long long val){    side[++cnt].v=y;    side[cnt].u=x;    side[cnt].next=first[x];    side[cnt].val=val;    first[x]=cnt;}inline void dfs(int root){    for(int i=first[root];i;i=side[i].next)        if(side[i].v!=fa[root])        {            fa[side[i].v]=root;            dfs(side[i].v);            son[root]+=son[side[i].v];        }}int main(){    n=read();       for(int i=2;i<=n;++i)    {        int x,y;    long long val;          x=read();y=read();val=read();        add(x,y,val);   add(y,x,val);           son[i]=1;    }    son[1]=1;   dfs(1);     for(int i=1;i<=cnt;++i)    {        int o=min(son[side[i].v],son[side[i].u]);        long long j=(long long)o*(long long)(n-o);        j%=nod; j*=side[i].val;        j%=nod; ans+=j;        ans%=nod;    }    cout<<ans<<endl;        return 0;}

感想

暴力出奇迹
然后平时多做些有关树和Dp的题
(话说Dp我还没搞。。。orz)

原创粉丝点击