zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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("
    ");
    }
    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;
    }
    
  • 相关阅读:
    Python安装(小白教程)中文版Pycharm
    二叉树遍历1
    node* p 和 node *p 和 node * p 的区别
    WinForm中的ListBox组件编程
    C# winform listBox中的项上下移动(转)
    C# ListBox 左移、右移、上移、下移
    C#上移,下移TreeView中的树节点顺序
    C#遍历DataSet与DataSet元素实现代码
    C# 手动编写 DataSet,DataTable 及遍历DataSet中的数据
    【.NET】C#中遍历各类数据集合的方法
  • 原文地址:https://www.cnblogs.com/zj75211/p/7695748.html
Copyright © 2011-2022 走看看