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;
}
原文地址:https://www.cnblogs.com/zj75211/p/7695748.html