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)
- tEST 3 for NOIP
- Test 3 for NOIP- Result for Day2
- *TEST 3 for NOIP 哈希有毒
- Test 5 for NOIP
- Test 7 for NOIP
- Test 6 for NOIP
- Test 10 for NOIP
- tEST 2 for NOIP
- *TEST 1 for NOIP
- *TEST 5 for NOIP 。。。
- *TEST 6 for NOIP + NOIP初赛
- Test 1 for NOIP: Result for Day1
- Test 1 for NOIP: Result for Day2
- Test 2 for NOIP- Result for Day1
- Test 2 for NOIP- Result for Day2
- Test 4 for NOIP- Result for Day1
- Test 4 for NOIP- Result for Day2
- Test 8 for NOIP- Result for Day1
- jquery实现2048游戏
- cqyz#递归-p3531 约瑟夫问题【6】
- fork and vfork
- ubuntu下opencv在Qt中的使用
- Django学习(六)(模板templates)
- tEST 3 for NOIP
- 《多合一麻将》(手机端+服务器+网站后台)全套完整源码下载
- HDFS集群繁忙时删除大量的文件导致NameNode服务不可用原理解析
- IDEA 连接mysql数据库
- 小鸟
- thinking in java——持有对象
- JDBC PreparedStatement实现数据库增删改查案例
- openstack 创建虚拟机
- jupyter notebook 多个python kernel配置