【浮*光】#省选真题# [FJOI2018] 领导集团 + 宝藏 + 邮递员问题
三道神奇至极的题目...完全动不了手...这个FJOI真的有点厉害啊...
出题水平呵呵...连部分分都没有...体验极差...
#include <cmath> #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <algorithm> #include <queue> #include <stack> #include <map> using namespace std; typedef long long ll; typedef unsigned long long ull; #define R register /*【p4577】领导集团问题 公司是一棵领导树。每个成员对应于树中一个结点vi,级别为wi(越高层的领导wi越小)。 树中任何两个结点之间有边相连,则表示与结点相应的两个成员属于同一部门。 在树中寻找最大部门结点子集,使得任意结点vi和vj,如果vi是vj的子孙,则wi≥wj。*/ //【分析】找树的每条路径上的LIS?但要结合树的性质... // 应该是树形f吧...f[i][0/1]以i为根节点的子树,不选/选择i的最多人数。 // f[i][0]=∑max(f[son][0],f[son][1]);f[i][1]+=...(然后发现写不下去了...) // 很不要脸的去看了题解...线段树合并?启发式合并?(说到数据结构就脑壳疼0x0) // 看到一篇奇奇怪怪的n^2题解,有意思233 // 后排%dalao https://www.luogu.org/blog/yestoday/solution-p4577 /*【思路1】首先考虑将所有的点按权值从大到小(权值相同就按深度从大到小)加入树中, 每个点暴力向父节点跳,并不断给该节点的f数组++,如果到了访问过的点就退出,并将该节点标记为未访问。*/ void reads(int &x){ //读入优化(正负整数) int fx_=1;x=0;char ch_=getchar(); while(ch_<'0'||ch_>'9'){if(ch_=='-')fx_=-1;ch_=getchar();} while(ch_>='0'&&ch_<='9'){x=x*10+ch_-'0';ch_=getchar();} x*=fx_; //正负号 } const int M=200019; struct Edge{ int ver,nextt; }e[M<<1]; int n,tot=0,ans,a[M],id[M],head[M],rk[M]; map<int,int> f[M]; void add(int u,int v){ e[++tot]=(Edge){v,head[u]},head[u]=tot; } bool cmp(int x,int y){ return a[x]<a[y]; } void merge(int p1,int p2){ if(f[p1].size()<f[p2].size()) swap(f[p1],f[p2]); for(map<int,int>::iterator it=f[p2].begin(); it!=f[p2].end();++it) f[p1][it->first]+=it->second; } void dfs(int u){ for(int i=head[u];i;i=e[i].nextt) dfs(e[i].ver),merge(u,e[i].ver); int fk=rk[u]-1; if( f[u].begin()->first > fk ) return; map<int,int>::iterator it=f[u].upper_bound(fk); it--; if( it->second == 1 ) f[u].erase(it); else it->second--; } int main(){ reads(n); for(int i=1;i<=n;i++) reads(a[i]),id[i]=i; for(int i=2,fa_;i<=n;i++) reads(fa_),add(fa_,i); sort(id+1,id+1+n,cmp),rk[id[1]]=1; //编号按权值大小排序,并记录排名 for(int i=2;i<=n;i++) rk[id[i]]=(a[id[i]]==a[id[i-1]])?rk[id[i-1]]:i; for(int i=1;i<=n;i++) f[i][rk[i]]=1; dfs(1); int anss=0; for(map<int,int>::iterator it=f[1].begin();it!=f[1].end();it++) anss+=it->second; printf("%d\n",anss); }
#include <cmath> #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <algorithm> #include <queue> #include <stack> #include <map> using namespace std; typedef long long ll; typedef unsigned long long ull; #define R register //【p4578】所罗门王的宝藏 //神奇的题目??叫模拟吗?? void reads(int &x){ //读入优化(正负整数) int fx_=1;x=0;char ch_=getchar(); while(ch_<'0'||ch_>'9'){if(ch_=='-')fx_=-1;ch_=getchar();} while(ch_>='0'&&ch_<='9'){x=x*10+ch_-'0';ch_=getchar();} x*=fx_; //正负号 } #define N 1019 int n,m,k,x[N],y[N],v[N],d1[N][N],d2[N][N]; bool w1[N][N],w2[N][N],okk; int ask(int i,int j,int op) { if(op) return y[i]<y[j]?v[i]-v[j]:v[j]-v[i]; return x[i]<x[j]?v[i]-v[j]:v[j]-v[i]; } bool check(int i,int j){ if(x[i]==x[j]&&y[i]==y[j]&&v[i]!=v[j]) return false; //同个位置两颗宝石 if(y[i]==y[j]){ if(w1[x[i]][x[j]]&&d1[x[i]][x[j]]!=ask(i,j,0)) return false; d1[x[i]][x[j]]=d1[x[j]][x[i]]=ask(i,j,0),w1[x[i]][x[j]]=w1[x[j]][x[i]]=1; } if(x[i]==x[j]){ if(w2[y[i]][y[j]]&&d2[y[i]][y[j]]!=ask(i,j,1)) return false; d2[y[i]][y[j]]=d2[y[j]][y[i]]=ask(i,j,1),w2[y[i]][y[j]]=w2[y[j]][y[i]]=1; } return true; //同一列:c1−c2=r1[i1]−r1[i2]...判断得到此位置暂时满足题意 } int main(){ int T; reads(T); while(T--){ memset(d1,0,sizeof(d1)),memset(d2,0,sizeof(d2)); memset(w1,0,sizeof(w1)),memset(w2,0,sizeof(w2)); reads(n),reads(m),reads(k); okk=1; //每次okk要初始化为1 for(int i=1;i<=k;i++) reads(x[i]),reads(y[i]),reads(v[i]); for(int i=1;i<=k&&okk;i++) for(int j=i+1;j<=k&&okk;j++) okk=check(i,j); printf(okk?"Yes\n":"No\n"); } }
#include <cmath> #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <algorithm> #include <queue> #include <stack> #include <map> using namespace std; typedef long long ll; typedef unsigned long long ull; #define R register //【p4579】邮递员问题 //超级神奇的dp??? //给定平面上若干个点,保证这些点在两条平行线(第0/1行)上, //给定起点终点,求从起点出发,遍历所有点后到达终点的最短路径长度。 /*【分析】强制令起点的位置是第0行。在第0行枚举一个i,在第一行枚举一个j。 f[j][0]:第0行[i~n0]这些点已经走完,第1行[j+1~n1]走完,即从此点到达终点的最短路。 f[j][1]:第0行[i+1~n0]已经走完,第1行[j~n1]走完,即从此点到达终点的最短路。 把i按照从前往后或者从后往前的顺序枚举,到达起点就直接更新答案。 因为从起点出发可以向两个方向走,所以前后都要做一遍dp。*/ void reads(int &x){ //读入优化(正负整数) int fx_=1;x=0;char ch_=getchar(); while(ch_<'0'||ch_>'9'){if(ch_=='-')fx_=-1;ch_=getchar();} while(ch_>='0'&&ch_<='9'){x=x*10+ch_-'0';ch_=getchar();} x*=fx_; //正负号 } #define MAX 10100 int n[2],ty[2],pos[2]; double h,tx[2],x[2][MAX],f[MAX][2]; double dis(int i,int j){ double d=fabs(x[0][i]-x[1][j]); return sqrt(d*d+h*h); } double ToEnd(int i,int j){ double d=fabs(x[i][j]-tx[1]); return i==ty[1]?d:sqrt(h*h+d*d); } double Calc(){ double ret=1e18; sort(&x[0][1],&x[0][n[0]+1]),sort(&x[1][1],&x[1][n[1]+1]); for(int i=n[0];i;--i){ if(i==n[0]){ for(int j=n[1];j;--j){ f[j][0]=j==n[1]?ToEnd(0,n[0]):min(f[j+1][1]+dis(n[0],j+1), dis(n[0],n[1])+x[1][n[1]]-x[1][j+1]+ToEnd(1,j+1)); f[j][1]=j==n[1]?ToEnd(1,n[1]):f[j+1][1]+x[1][j+1]-x[1][j]; } continue; } for(int j=n[1];j;--j) if(j==n[1]){ f[j][1]=min(f[j][0]+dis(i+1,j),dis(n[0],n[1])+x[0][n[0]]-x[0][i+1]+ToEnd(0,i+1)); f[j][0]+=x[0][i+1]-x[0][i]; } else{ f[j][1]=min(f[j][0]+dis(i+1,j),f[j+1][1]+x[1][j+1]-x[1][j]); f[j][0]=min(f[j][0]+x[0][i+1]-x[0][i],f[j+1][1]+dis(i,j+1)); } ret=min(ret,x[0][i]-x[0][1]+tx[0]-x[0][1]+dis(i,1)+f[1][1]); ret=min(ret,fabs(x[0][i]-tx[0])+x[0][i]-x[0][1]+dis(1,1)+f[1][1]); if(x[0][i]<=tx[0]){ ret=min(ret,tx[0]-x[0][1]+dis(1,1)+f[1][1]); break; } } return ret; } int main(){ reads(n[0]),reads(n[1]),reads(ty[0]),reads(pos[0]); reads(ty[1]),reads(pos[1]),scanf("%lf",&h); int r=0; if(ty[0]) r=1,swap(n[0],n[1]),ty[0]^=1,ty[1]^=1; //强制第0行开始 for(int t=0;t<=1;t++) for(int i=1;i<=n[t^r];i++) scanf("%lf",&x[t^r][i]); tx[0]=x[ty[0]][pos[0]]; tx[1]=x[ty[1]][pos[1]]; double ans=Calc(); for(int t=0;t<=1;t++) for(int i=1;i<=n[t];i++) x[t][i]=20000-x[t][i]; tx[0]=20000-tx[0]; tx[1]=20000-tx[1]; printf("%.2lf\n",min(ans,Calc())); }
——时间划过风的轨迹,那个少年,还在等你