蒟蒻考前攒人品
1.noip2014 联合权值:
分析:
1.,给定一个无向图,要求所有距离为2的点的有序数对的权值乘积之和即最大值 2.距离为2显然不需要dfs,与一个点相连的两个点距离必定为2; 3.然后比如说一个点和a,b,c相连,那么答案应该是2ab+2bc+2ac=(a+b+c)*(a+b+c)-a*a-b*b-c*c; 5.即我们只需要扫过每一个点,在扫一遍与其相连的点,记录权值和跟每个权值的平方,权值和的平方-每个权值的平方即为该点的贡献,至于最大值,肯定是最大跟第二大
乘,记录下来即可,没必要想我一样强行sort;
上标程:
#include<iostream> #include<algorithm> #include<vector> #include<cstdio> #include<cstring> using namespace std; vector<int> a[200000]; long long tot,ans,maxn,tot1,tot2,max1,max2,w[200010],c[200010]; int gi() { int x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } int main() { int n,u,v; cin>>n; for(int i=1;i<n;i++) { u=gi(),v=gi(); a[u].push_back(v); a[v].push_back(u); } for(int i=1;i<=n;i++) { w[i]=gi(); } for(int i=1;i<=n;i++) { tot1=0,tot2=0; for(int j=0;j<a[i].size();j++) { tot1+=w[a[i][j]]; tot1%=10007; tot2+=w[a[i][j]]*w[a[i][j]]; tot2%=10007; c[j]=w[a[i][j]]; } sort(c,c+a[i].size()); maxn=max(maxn,c[a[i].size()-1]*c[a[i].size()-2]); tot+=tot1*tot1-tot2; tot%=10007; } cout<<maxn<<' '<<tot; } 2.noip2014 寻找道路分析:
1.给定有向图,要在满足该路径上所有的点的出边都直接或间接的与终点相连的条件下的最短路径 2.如何满足该路径上的点的出边都直接或间接的于终点相连呢? 3.从终点开始dfs,对经历的每个点进行染色,那么被染色的点必定是直接或间接于终点相连的 4.然后O(n)check一遍每个没有被染上色的点,然后把和他相连的点变为没染色(还要多开一个 flag[]表示该点是不是有上步操作而变为没被染色的(如果是因为由上步操作而变为0的不能把和他连的 点变为0)) 5.最后起点到终点的对被染色的点最短路跑一遍bfs即可
上标程
#include<iostream> #include<cstdio> #include<vector> using namespace std; int gi() { int x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } vector <int>e[200010]; int r[200010],c[200010],qd,zd,vis[200010],ans,flag[200010]; struct sb { int x,step; } a[400020]; void dfs(int x) { for(int i=0; i<e[x].size(); i++) { if(vis[e[x][i]]==0) { vis[e[x][i]]=1; dfs(e[x][i]); } } } void bfs(int x) { int t=0,sum=0; a[0].x=x,a[0].step=0; while(t<=sum) { for(int i=0; i<e[a[t].x].size(); i++) { if(vis[e[a[t].x][i]]==1) { a[++sum].x=e[a[t].x][i]; a[sum].step=a[t].step+1; if(e[a[t].x][i]==qd) { ans=a[sum].step; return; } vis[e[a[t].x][i]]=2; } } t++; } ans=-1; return; } int main() { int n,m,u,v; cin>>n>>m; for(int i=1; i<=m; i++) { u=gi(),v=gi(); e[v].push_back(u); r[v]++; c[u]++; } cin>>qd>>zd; dfs(zd); for(int i=1; i<=n; i++) { if(vis[i]==0&&i!=zd) { if(flag[i]==0) { for(int j=0; j<e[i].size(); j++) { vis[e[i][j]]=0; flag[e[i][j]]=1; } } } } bfs(zd); cout<<ans; }3.舒适的路线:分析:
1.给定一个无向图,要求使两点联通的路径中权值最大值与最小值的比最小
2.我们先按边sort一遍,然后枚举最小边开始构出一条是两点联通的路径,(构法类似于最小生成树),如果判断两点联通?用并查集,即两点
联通后就break,因为后面加进来的边会更大,然后在构边的时候可以记录最大值和最小值,然后每次比较即可。
上标程:
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; int fa[10000],ans[10]; double ans1=999999; int gcd(int x,int y) { return y?gcd(y,x%y):x; } int find(int x) { if(x!=fa[x]) { fa[x]=find(fa[x]); } return fa[x]; } struct sb { int x,y,v; } p[10000000]; bool cmp(sb a,sb b) { return a.v<b.v; } int gi() { int x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } int main() { int n,m,s,t; n=gi(),m=gi(); for(int i=1; i<=m; i++) { p[i].x=gi(),p[i].y=gi(),p[i].v=gi(); } cin>>s>>t; sort(p+1,p+1+m,cmp); for(int i=1; i<=m; i++) { int minn=999999999,maxn=0,flag=0; for(int j=1; j<=n; j++) fa[j]=j; for(int j=i; j<=m; j++) { int X=find(p[j].x),Y=find(p[j].y); if(X!=Y) { fa[X]=Y; minn=min(minn,p[j].v); maxn=max(maxn,p[j].v); } if(find(s)==find(t)) { flag=1; break; } } if((ans1>((double)maxn/(double)minn))&&maxn&&flag) { ans1=(double)maxn/(double)minn; ans[1]=maxn,ans[2]=minn; } } if(ans1==999999) cout<<"IMPOSSIBLE"; else { int G=gcd(ans[1],ans[2]); ans[1]/=G,ans[2]/=G; if(ans[2]==1) { cout<<ans[1]; } else { cout<<ans[1]<<"/"<<ans[2]; } } }4.极差最小生成树的板子:方法类似,也是枚举最小边 #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; int gi() { int x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } struct sb { int x,y,w; } p[100000]; int fa[1000000],MAX,MIN=999999999,ans=999999999; int find(int x) { if(x!=fa[x]) { fa[x]=find(fa[x]); } return fa[x]; } bool cmp(sb a,sb b) { return a.w<b.w; } int main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); int T,n,m; sb x,y; cin>>T; while(T--) { n=gi(),m=gi(); ans=999999999; for(int i=1; i<=m; i++) { p[i].x=gi(),p[i].y=gi(),p[i].w=gi(); } sort(p+1,p+1+m,cmp); for(int i=1; i+n-2<=m; i++) { MAX=0,MIN=999999999; int len=0,flag=0; for(int j=1; j<=n; j++) { fa[j]=j; } for(int j=i; j<=m; j++) { int x1=find(fa[p[j].x]),y1=find(fa[p[j].y]); if(x1!=y1) { fa[x1]=y1; MAX=max(MAX,p[j].w); MIN=min(MIN,p[j].w); len++; } if(len==n-1) { ans=min(ans,MAX-MIN); break; } } } if(ans==999999999) { cout<<-1<<endl; } else cout<<ans<<endl; } }5.一道与信息传递类似的题:NiroBC在温暖的YYHS衣来伸手饭来张口,过着颓废的生活。
终于有一天,她意识到,真正有意义的人生不应该在如此空虚的时光中度过,于是她下定决心,来到了百废待兴的新世界,踏上了寻找人生的意义的旅途。
这个百废待兴的新世界啊真是美妙,绽放着令人惊喜的异彩,NiroBC欢笑着投入了新世界的怀抱,随机的降落在这个新世界中。
这个新世界由N个城市组成(编号为1..N),每个城市中都能找到特定价值的人生意义,其中第i个城市的意义大小为W[i]。
NiroBC渐渐熟悉了这个世界的规律,她发现人世间发生的一切都是注定的,不可能因为世界的一个小部分————也就是人的个体————的意志而改变。既然一切都是注定的,那么每个城市都有一个唯一的后继城市a[i]。也就是说,当NiroBC当前在城市i时,下一时刻她将不可选择地来到a[i]。
设NiroBC最初降落在城市x,那么她将按照x -> a[x] -> a[a[x]] -> a[a[a[x]]] -> ...的路径行走,永远不会停止,并且得到沿途的人生意义。然而人生不能单调,同一个城市的人生意义只能得到一次,NiroBC最终得到的人生意义是所有经过的城市(不重复)的人生意义的和。
NiroBC是等概率地随机地降落在N个城市中的,她想知道她最终得到的人生的意义的期望值。(即所有人生意义的和的平均值)
分析:
1.首先环上的点的人生意义是一样的,对吧,我们可以先删掉链,然后给每个环打上不同标记,开数组记下每个环的权值及大小,就可以把环上的点的值都算出来了
2.链上的点怎么处理,一直跳爸爸,直到跳到了一个环上的点,那么加上这个环的权值就可以break了
上标程
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; long long gi() { long long x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } long long a[300010],w[300010],r[300010],v[300010],r0[300010],tot,color,ans; struct sb { long long mean,num; }p[300010]; void dfs(long long now,long long goal,long long color,long long mean,long long dep) { v[now]=color; if(now==goal&&mean!=w[now]) { p[color].mean=mean-w[now],p[color].num=dep-1; return; } dfs(a[now],goal,color,mean+w[a[now]],dep+1); } int main() { freopen("meaning.in","r",stdin); freopen("meaning.out","w",stdout); long long n; n=gi(); for(long long i=1; i<=n; i++) { a[i]=gi();r[a[i]]++; } long long flag=0; while(1) { flag=0; for(long long i=1;i<=n;i++) { if(r[i]==0&&v[i]==0) { r0[++tot]=i; flag=1; v[i]=1; r[a[i]]--; } } if(flag==0) break; } for(long long i=1; i<=n; i++) w[i]=gi(); color=1; for(long long i=1;i<=n;i++) { if(v[i]==0) { color++; dfs(i,i,color,w[i],1); ans+=p[color].mean*p[color].num; } } for(long long i=1;i<=tot;i++) { while(v[r0[i]]==1) { ans+=w[r0[i]]; r0[i]=a[r0[i]]; } ans+=p[v[r0[i]]].mean; } double fans=(double)ans/(double)n; printf("%.6f",fans); return 0; }6.剩下的就是一堆最短路和lca的题了,板子一定要会敲noip 2016 rp++;