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

浙公网安备 33010602011771号