17.11.08
- 上午 模拟考试
- Prob.1(WA30)
模拟,有点小烦。然后double转整型时没有long long,挂了3个点。
- Prob.2(WA70)
简化题目
给出了一个图(n点数<=2500)的两点间的最短距离的邻接矩阵。
问是否存在一颗 n个点的树的邻接矩阵和输入的相同。 (没有负权)
可以发现,如果存在的话,当前邻接表中最小的边一定是树中的一条边。
所以就 最小生成树prim算法,不用优先队列 n^2
然后就是求出当前树的两点间距离的邻接矩阵。比对就好了。
跑n次dfs就出来了 n^2
(智障的我:怎么求树上所有点之间的距离啊,Floyd n^3 要炸啊。简直莫法做,看来只能得30分了)
(、、、、Floyd?!蛤,我在干嘛、、)
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define MAXN 2505 #define INF 0x3f3f3f3f using namespace std; struct edge{ ll to,val,next; }e[MAXN*2]; ll ans[MAXN][2]; ll head[MAXN],fa[MAXN],mp[MAXN][MAXN],dis[MAXN][MAXN]; ll n,ent; char gc(){ static char s[100005]; static int bit=100000,p,len; if(p>=len) len=fread(s,1,bit,stdin),s[len]=EOF,p=0; return s[p++]; } void read(ll &x){ static int f;static char ch; x=0; f=1; ch=gc(); while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=gc();} while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=gc();} x=x*f; } void add(ll u,ll v,ll w){ e[ent]=(edge){v,w,head[u]}; head[u]=ent++; } void Prim(){ static ll d[MAXN],from[MAXN]; static bool vis[MAXN]; memset(vis,0,sizeof(vis)); memset(d,0x3f,sizeof(d)); memset(head,0,sizeof(head)); vis[1]=1; ent=2; for(ll i=2;i<=n;i++) if(d[i]>mp[1][i]) d[i]=mp[1][i],from[i]=1; for(ll k=1,w,v;k<n;k++){ w=INF; for(ll i=1;i<=n;i++) if(!vis[i]&&w>d[i]) w=d[i],v=i; add(from[v],v,w); add(v,from[v],w); vis[v]=1; ans[from[v]][0]+=w; ans[v][0]+=w; ans[from[v]][1]+=1; ans[v][1]+=1; for(ll i=1;i<=n;i++) if(!vis[i]&&d[i]>mp[v][i]) d[i]=mp[v][i],from[i]=v; } } void dfs(ll u,ll dad,ll val,ll *DIS){ DIS[u]=val; for(ll i=head[u];i;i=e[i].next){ ll v=e[i].to; if(v==dad) continue; dfs(v,u,val+e[i].val,DIS); } } void check(){ bool fg=1; for(ll i=1;i<=n;i++) for(ll j=1;j<=n;j++) if(dis[i][j]!=mp[i][j]){fg=0;break;} if(!fg) printf("No\n"); else{ double val=1.0*ans[1][0]/ans[1][1];ll ANS=1; for(ll i=2;i<=n;i++) if(1.0*ans[i][0]/ans[i][1]>val) val=1.0*ans[i][0]/ans[i][1],ANS=i; printf("Yes\n%I64d\n",ANS); } } void work(){ read(n); for(ll i=1;i<=n;i++) for(ll j=1;j<=n;j++) read(mp[i][j]); Prim(); for(ll i=1;i<=n;i++) dfs(i,0,0,dis[i]); check(); } void init(){ memset(ans,0,sizeof(ans)); memset(dis,0,sizeof(dis)); ent=0; } int main(){ freopen("treas.in","r",stdin); freopen("treas.out","w",stdout); ll T; read(T); while(T--){ init(); work(); } return 0; }
- Prob.3(WA10)
- 一个处理区间覆盖的题。他们都大佬地用O(n)做,我却在弱弱地用线段树维护、、、(就当复习了。)
-
注意!!!
1).这种题用到线段树的话,是以单位区间为底层节点的,方便。
2).离散化后,要在没有紧贴的点中间加入一些 "占位点")
(要不是数据善良,不然今天就又凉了)
- 补两个Tyvj上的题,之前忘了记录了。
- Tyvj P1480 星际大战
状压dp,
dp[S]表示选了"目标"集合为S的元素,这些元素依次被前几个导弹攻击的最小距离和。
然后刷表法,即枚举下一个导弹打哪个目标。
复杂度:2^n*n
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> using namespace std; const double eps=1e-6; struct pos{ int x,y; }mis[25],aim[25]; double d[25][25],dp[1<<20],hv[1<<20]; int n,all; int idx(int i){ return 1<<i; } int sign(double x){ if(fabs(x)<=eps) return 0; return x>0?1:-1; } void cmin(double &a,double b){ if(sign(a-b)>0) a=b; } double dis(pos a,pos b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } int main(){ scanf("%d",&n); all=(1<<n)-1; for(int i=0;i<n;i++) scanf("%d%d",&mis[i].x,&mis[i].y); for(int i=0;i<n;i++) scanf("%d%d",&aim[i].x,&aim[i].y); for(int i=0;i<n;i++) for(int j=0;j<n;j++) d[i][j]=dis(mis[i],aim[j]); for(int S=1;S<=all;S++) hv[S]=hv[S>>1]+(S&1),dp[S]=1e9; for(int S=0,p;S<all;S++) for(int i=0;i<n;i++){ if(S&idx(i)) continue; p=hv[S]; cmin(dp[S|idx(i)],dp[S]+d[p][i]); } printf("%.3lf",dp[all]); return 0; }
- Tyvj P4112 删数问题
贪心,依次确定最高位。
显然在可取范围内,最高位越小越好,那么每次就查询可行区间的最小值的位置。
线段树维护(尝试了一下ZKW线段树,感觉很像镜像对称后的树状数组。)
(但是不会区间修改,感觉好麻烦啊,需要区间修改是我还是先直接打线段树吧)
代码:
#include<cstring> #include<iostream> #define MAXN 800 using namespace std; char s[300],ans[300]; struct ZKW{ int mini[MAXN],pos[MAXN],M,N; void update(int &fmini,int &fpos,int smini,int spos){ if(fmini<smini) return; if(fmini==smini&&fpos<spos) return; fmini=smini; fpos=spos; } void build(int n){ memset(mini,0x3f,sizeof(mini)); for(M=1;M<=n+1;M<<=1); N=n; for(int i=1;i<=n;i++) mini[M+i]=s[i]-'0',pos[M+i]=i; for(int i=M;i;i--) update(mini[i],pos[i],mini[i<<1],pos[i<<1]), update(mini[i],pos[i],mini[i<<1|1],pos[i<<1|1]); } int query(int l,int r){ int v=0x3f3f3f3f,p; l=M+l-1; r=M+r+1; for(;l^r^1;l>>=1,r>>=1){ if(~l&1) update(v,p,mini[l^1],pos[l^1]); if(r&1) update(v,p,mini[r^1],pos[r^1]); } return p; } }T; int main(){ int n,m,k,cnt=0,now=0; scanf("%s",s+1); n=strlen(s+1); T.build(n); int last=0; scanf("%d",&m); k=n-m; while(k){ int p=T.query(last+1,last+m+1); ans[++cnt]=s[p]; m-=(p-last-1); k--; last=p; }; for(int i=1;i<=cnt;i++) now=now*10+ans[i]-'0'; printf("%d",now); return 0; }
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas