17.10.19
- 上午
- BZOJ 1050 [HAOI2006]旅行comf
真的是醉了,
边数这么小,都可以支持n^2,
排序后,直接枚举最小边,然后依次插入大边直到s t联通,并查集维护。
当时还想了好久,真是zz。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; struct edge{ int u,v,w; bool operator <(const edge &rtm) const{ return w<rtm.w; } }e[5005]; int fa[505]; int n,m,nowmin,nowmax,ansmin,ansmax,s,t; double ans=1e9; int gcd(int a,int b){ while(a^=b^=a^=b%=a); return b; } int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); scanf("%d%d",&s,&t); sort(e+1,e+m+1); for(int i=1;i<=m;i++){ nowmin=e[i].w; for(int j=1;j<=n;j++) fa[j]=j; for(int j=i;j<=m;j++){ int fu=find(e[j].u),fv=find(e[j].v); if(fu==fv) continue; fa[fv]=fu; int fs=find(s),ft=find(t); if(fs==ft){ nowmax=e[j].w; if(1.0*nowmax/nowmin<ans){ ans=1.0*nowmax/nowmin; ansmax=nowmax; ansmin=nowmin; break; } } } } if(ans>=1e9) printf("IMPOSSIBLE"); else{ int g=gcd(ansmax,ansmin); printf("%d",ansmax/g); if(ansmin!=g) printf("/%d",ansmin/g); } return 0; }
- BZOJ 1051 [HAOI2006]受欢迎的牛
Tarjan 缩点
最后如果存在非零的答案的话,必然有且仅有一个出度为0的强连通分量。
这个强连通分量的大小就是答案。
代码:
#include<cstdio> #include<cstring> #include<iostream> #define MAXN 10005 using namespace std; struct edge{ int to,next; }e[50005]; int head[MAXN],belong[MAXN],out[MAXN]; int stack[MAXN],dfn[MAXN],low[MAXN],ins[MAXN],siz[MAXN],tim,cnt,top; int n,m,ent=2,ans; void add(int u,int v){ e[ent]=(edge){v,head[u]}; head[u]=ent++; } void Tarjan(int u){ int v; dfn[u]=low[u]=++tim; stack[++top]=u; ins[u]=1; for(int i=head[u];i;i=e[i].next){ v=e[i].to; if(!dfn[v]) Tarjan(v),low[u]=min(low[u],low[v]); else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]!=low[u]) return; ++cnt; do{ v=stack[top--]; ins[v]=0; belong[v]=cnt; siz[cnt]++; }while(dfn[v]!=low[v]); } int main(){ scanf("%d%d",&n,&m); for(int i=1,a,b;i<=m;i++){ scanf("%d%d",&a,&b); add(a,b); } for(int i=1;i<=n;i++)if(!dfn[i]) Tarjan(i); for(int u=1;u<=n;u++) for(int i=head[u];i;i=e[i].next){ int v=e[i].to; int uu=belong[u],vv=belong[v]; if(uu==vv) continue; out[uu]++; } for(int i=1;i<=cnt;i++){ if(!out[i]&&ans) {printf("0"); return 0;} if(!out[i]) ans=siz[i]; } printf("%d",ans); return 0; }
- BZOJ 1052 [HAOI2007]覆盖问题
二分答案
枚举枚举四个角。
代码:
#include<cstdio> #include<cstring> #include<iostream> #define INF 0x3f3f3f3f using namespace std; struct point{ int x,y; }p[20005]; bool vis[20005]; int n; void get(int &x1,int &y1,int &x2,int &y2){ x1=INF,y1=INF,x2=-INF,y2=-INF; for(int i=1;i<=n;i++)if(!vis[i]){ x1=min(x1,p[i].x); y1=min(y1,p[i].y); x2=max(x2,p[i].x); y2=max(y2,p[i].y); } } void cover(int x1,int y1,int x2,int y2,int *tmp,int &cnt){ cnt=0; for(int i=1;i<=n;i++){ if(!vis[i]&&x1<=p[i].x&&p[i].x<=x2&&y1<=p[i].y&&p[i].y<=y2) vis[i]=1,tmp[++cnt]=i; } } void uncover(int *tmp,int cnt){ for(int i=1;i<=cnt;i++) vis[tmp[i]]=0; } bool check(int len,int res){ if(res==0){ for(int i=1;i<=n;i++) if(!vis[i]) return 0; return 1; } int x1,y1,x2,y2,nx1,ny1,nx2,ny2,cnt,tmp[20005]; bool fg=0; get(x1,y1,x2,y2); //左下角 nx1=x1,ny1=y1,nx2=x1+len,ny2=y1+len; cover(nx1,ny1,nx2,ny2,tmp,cnt); fg=fg|check(len,res-1); uncover(tmp,cnt); if(fg) return 1; //左上角 nx1=x2-len,ny1=y1,nx2=x2,ny2=y1+len; cover(nx1,ny1,nx2,ny2,tmp,cnt); fg=fg|check(len,res-1); uncover(tmp,cnt); if(fg) return 1; //右下角 nx1=x1,ny1=y2-len,nx2=x1+len,ny2=y2; cover(nx1,ny1,nx2,ny2,tmp,cnt); fg=fg|check(len,res-1); uncover(tmp,cnt); if(fg) return 1; //右上角 nx1=x2-len,ny1=y2-len,nx2=x2,ny2=y2; cover(nx1,ny1,nx2,ny2,tmp,cnt); fg=fg|check(len,res-1); uncover(tmp,cnt); if(fg) return 1; return 0; } void binary(int r){ int l=0,mid,ans; while(l<=r){ mid=(l+r)/2; if(check(mid,3)) ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans); } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y); int x1,y1,x2,y2; get(x1,y1,x2,y2); int len=max(x2-x1,y2-y1); binary(len); return 0; }
- BOZJ 1053 [HAOI2007]反素数ant
和http://www.cnblogs.com/zj75211/p/7624024.html
中的 《入门OJ 2061: [Noip模拟题]最多的约数》差不多,只是这个题的质数表更小
注意取答案时 有两种情况:
一种是当前算出来的约数大于记录的最大约数
而是当前算出来的约数等于记录的最大约,但是当前的累乘出来的积小于记录的积
代码:
#include<cstdio> #include<cstring> #include<iostream> #define ll long long using namespace std; int prime[]={0,2,3,5,7,11,13,17,19,23,29,31}; ll n,ansyue,anspro; void dfs(int p,ll pro,ll yue,int last){ if((yue>ansyue)||(yue==ansyue&&pro<anspro)) anspro=pro,ansyue=yue; for(int i=1;i<=last;i++){ if(pro*prime[p]>n) break; pro*=prime[p]; dfs(p+1,pro,yue*(i+1),i); } } int main(){ scanf("%lld",&n); dfs(1,1,1,31); printf("%lld",anspro); return 0; }
- BOZJ 1054 [HAOI2008]移动玩具
把棋盘状态用二进制表示,最多(1<<16)-1个状态,
bfs即可
代码:
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #define node(a,b) (node){a,b} using namespace std; bool vis[1<<16]; struct node{ int u,w; }; int idx(int i,int j){ return (16-((i-1)*4+j)+1); } int bfs(int st,int ed){ queue<node>q; q.push(node(st,0)); while(!q.empty()){ int u=q.front().u,w=q.front().w,v; q.pop(); if(u==ed) return w; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { int id=idx(i,j)-1; if(!(u&(1<<id))) continue; if(i!=1&&!(u&(1<<(id+4)))){ //up v=u^(1<<id); v=v^(1<<(id+4)); if(!vis[v]) q.push(node(v,w+1)),vis[v]=1; } if(i!=4&&!(u&(1<<(id-4)))){ //down v=u^(1<<id); v=v^(1<<(id-4)); if(!vis[v]) q.push(node(v,w+1)),vis[v]=1; } if(j!=1&&!(u&(1<<(id+1)))){ //left v=u^(1<<id); v=v^(1<<(id+1)); if(!vis[v]) q.push(node(v,w+1)),vis[v]=1; } if(j!=4&&!(u&(1<<(id-1)))){ //right v=u^(1<<id); v=v^(1<<(id-1)); if(!vis[v]) q.push(node(v,w+1)),vis[v]=1; } } } return -1; } int main(){ int st=0,ed=0,x; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) scanf("%1d",&x),st=st<<1|x; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) scanf("%1d",&x),ed=ed<<1|x; int ans=bfs(st,ed); printf("%d",ans); return 0; }
- BOZJ 1055 [HAOI2008]玩具取名
记忆化搜索
f[l][r][k]:表示l~r区间是否可以合并成k字符
这个状态定义出来以后,转移就比较简单了。
就是枚举区间分为哪两段,然后看这两段区间是否可以分别形成组成k元素的那两个元素
代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; char alph[5]={0,'W','I','N','G'}; int to[5][20][3],a[205],len; bool f[205][205][5],vis[205][205][5]; int idx(char ch){ switch(ch){ case 'W' :return 1; case 'I' :return 2; case 'N' :return 3; case 'G' :return 4; } return -1; } bool dfs(int l,int r,int k){ if(vis[l][r][k]) return f[l][r][k]; vis[l][r][k]=1; bool &ret=f[l][r][k]; if(l==r) return ret=(a[l]==k); for(int i=1;i<=to[k][0][0];i++) for(int j=l;j<r;j++){ if(dfs(l,j,to[k][i][1])&dfs(j+1,r,to[k][i][2])) return ret=1; } return ret=0; } int main(){ char ch,s[205]; bool fg=0; scanf("%d%d%d%d",&to[1][0][0],&to[2][0][0],&to[3][0][0],&to[4][0][0]); for(int i=1;i<=4;i++) for(int j=1;j<=to[i][0][0];j++){ scanf(" %c",&ch); to[i][j][1]=idx(ch); scanf(" %c",&ch); to[i][j][2]=idx(ch); } scanf("%s",s); len=strlen(s); for(int i=0;i<len;i++) a[i+1]=idx(s[i]); for(int i=1;i<=4;i++) if(dfs(1,len,i)) fg=1,printf("%c",alph[i]); if(!fg) printf("The name is wrong!"); return 0; }
- 下午
- Lence选讲他的“插入DP”……
- 晚上
- BOZJ 1056 [HAOI2008]排名系统
Splay 维护
数据有毒,说好不超过8位正整数的,但却有数据都超过了0x3f3f3f3f,害得我调了半天,INF定为0x7f7f7f7f才过。
代码:
#include<map> #include<cstdio> #include<cstring> #include<iostream> #define MAXN 250005 #define INF 0x7fffffff using namespace std; struct node{ int siz,val; char name[15]; void New(int w,char *c){ siz=1; val=w; int i=0; while(c[++i]) name[i-1]=c[i]; name[i-1]=0; } }nd[MAXN]; char s[15]; map<string,int> mp; int ch[MAXN][2],fa[MAXN]; int n,rt,siz; void Pushup(int x){ //ok nd[x].siz=nd[ch[x][0]].siz+nd[ch[x][1]].siz+1; } void Rotate(int x,int &k){ int y=fa[x],z=fa[y],l=(ch[y][0]!=x),r=l^1; if(y==k) k=x; else ch[z][ch[z][0]!=y]=x; fa[x]=z; fa[y]=x; fa[ch[x][r]]=y; ch[y][l]=ch[x][r]; ch[x][r]=y; Pushup(y); } void Splay(int x,int &k){ int y,z; while(x!=k){ y=fa[x]; z=fa[y]; if(y!=k){ if((ch[z][0]==y)^(ch[y][0]==x)) Rotate(x,k); else Rotate(y,k); } Rotate(x,k); } Pushup(x); } void Insert(int &x,int last,int w,int id){ if(!x){x=id; nd[id].New(w,s); fa[x]=last; Splay(x,rt); return;} Insert(ch[x][nd[x].val<w],x,w,id); } void Erase(int x){ Splay(x,rt); int t1=ch[x][0],t2=ch[x][1]; while(ch[t1][1]) t1=ch[t1][1]; while(ch[t2][0]) t2=ch[t2][0]; Splay(t1,rt); Splay(t2,ch[rt][1]); fa[x]=0; ch[t2][0]=0; Pushup(t2); Pushup(t1); } void Rank(int id){ Splay(id,rt); printf("%d\n",nd[ch[rt][1]].siz+1-1); } int Number(char *c){ int w=0,i=0; while(c[++i]) w=w*10+c[i]-'0'; return w; } int Getid(int x,int res){ if(nd[ch[x][1]].siz>=res) return Getid(ch[x][1],res); if(res==nd[ch[x][1]].siz+1) return x; return Getid(ch[x][0],res-nd[ch[x][1]].siz-1); } void Print(int x,bool left){ if(!x) return; Print(ch[x][1],left&0); printf("%s",nd[x].name); if(ch[x][0]||!left) printf(" "); Print(ch[x][0],left&1); } void List(int a){ int b=min(a+1+10,siz); int end=Getid(rt,a),begin=Getid(rt,b); Splay(begin,rt); Splay(end,ch[rt][1]); Pushup(begin); Print(ch[end][0],1); printf("\n"); } int main(){ //freopen("1056.out","w",stdout); scanf("%d",&n); int id,w; Insert(rt,0,-INF,++siz); Insert(rt,0,INF,++siz); while(n--){ scanf("%s",s); id=mp[s+1]; if(s[0]=='+'){ scanf("%d",&w); //if(w>0x3f3f3f3f) printf("fuck"); if(!id) id=++siz,mp[s+1]=siz; else Erase(id); Insert(rt,0,w,id); } else if('A'<=s[1]&&s[1]<='Z') Rank(id); else { w=Number(s); List(w); } } return 0; }
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas