BJOI2015 Day1

本以为会是三道小强与阿米巴,结果打开题目一看发现了这个:

 

 

 

 

T1:

恩先写着一道

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
using namespace std;
inline int read() {
    char ch=getchar();int x=0,f=1;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
const int maxn=100010;
const int maxnode=2000010;
int A[maxn],B[maxn],root[maxn];
int ls[maxnode],rs[maxnode],s[maxnode],ToT;
void build(int& y,int x,int l,int r,int pos) {
     s[y=++ToT]=s[x]+1;if(l==r) return;
     int mid=l+r>>1;ls[y]=ls[x];rs[y]=rs[x];
     if(pos<=mid) build(ls[y],ls[x],l,mid,pos);
     else build(rs[y],rs[x],mid+1,r,pos);     
}
int query(int y,int x,int l,int r,int k) {
    if(l==r) return l;
    int k2=s[ls[y]]-s[ls[x]],mid=l+r>>1;
    if(k<=k2) return query(ls[y],ls[x],l,mid,k);
    return query(rs[y],rs[x],mid+1,r,k-k2);    
}
int main() {
    freopen("kth.in","r",stdin);
    freopen("kth.out","w",stdout);
    int n=read(),q=read();
    rep(1,n) A[i]=B[i]=read();
    sort(B+1,B+n+1);
    rep(1,n) build(root[i],root[i-1],1,n,lower_bound(B+1,B+n+1,A[i])-B);
    rep(1,q) {
        int l=read(),r=read(),k=read();
        printf("%d\n",B[query(root[r],root[l-1],1,n,r-l-k+2)]);         
    }
    return 0;
}
View Code

 

T2:

无脑爆搜+调整顺序,只搞出来5个点。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
using namespace std;
inline int read() {
    char ch=getchar();int x=0,f=1;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
int cnt;
char s[20][20];
int rr[423],ry[324];
int id(int x,int y) {return (((y-1)/4)*4+(x-1)/4)+1;}
int r[20][20],c[20][20],sq[20][20],num[20][20],use[17];
struct Point {
    int x,y,s;
    bool operator < (const Point& ths) const {
         return rr[x]+ry[num[x][y]]>rr[ths.x]+ry[num[x][y]];//s>ths.s;
    }    
}A[410];
void dfs(int cur) {
     if(cur==cnt+1) {
          rep(i,1,16) {
              rep(j,1,16) putchar(s[i][j]);
              puts("");
          }
          exit(0);
     }     
     else {
          int x=A[cur].x,y=A[cur].y,z=num[x][y];
          for(int d=1;d<=16;d++) if(!r[x][d]&&!c[y][d]&&!sq[z][d]){
              r[x][d]=c[y][d]=sq[z][d]=1;use[d]++;
              s[x][y]=(d<=10?d-1+'0':d-11+'A');dfs(cur+1);
              r[x][d]=c[y][d]=sq[z][d]=0;use[d]--;
          }
     }
}
int sc[1010];
int main() {
    srand(time(0));
    rr[6]=17;rr[7]=876;rr[10]=16;rr[12]=12;ry[10]=38;ry[6]=34;
    freopen("sixteen7.in","r",stdin);
    freopen("sixteen7.out","w",stdout);
    sc['0']=1;sc['1']=2;sc['2']=3;sc['3']=4;
    sc['4']=5;sc['5']=6;sc['6']=7;sc['7']=8;
    sc['8']=9;sc['9']=10;sc['A']=11;sc['B']=12;
    sc['C']=13;sc['D']=14;sc['E']=15;sc['F']=16;
    rep(i,1,16) scanf("%s",s[i]+1);
    rep(i,1,16) rep(j,1,16) {
        num[i][j]=id(i,j);
        if(s[i][j]=='.') {
            A[++cnt]=(Point){i,j,0};
            rep(k,1,16) if(s[i][k]!='.') A[cnt].s++;
            rep(k,1,16) if(s[k][j]!='.') A[cnt].s++;
            rep(k,1,16) rep(k2,1,16) if(s[k][k2]!='.'&&id(k,k2)==id(i,j)) A[cnt].s++;
            if(i==6||i==7||i==10) A[cnt].s+=200;
        }
        else {
            r[i][sc[s[i][j]]]=1;c[j][sc[s[i][j]]]=1;
            sq[num[i][j]][sc[s[i][j]]]=1;
        }
    }
    /*for(int i=1;i<cnt;i++)
      for(int j=i+1;j<=cnt;j++)
        if(A[j].x==6&&(A[i].x!=7)) swap(A[i],A[j]);
        else if(A[j].x==7) swap(A[i],A[j]);
        else if(A[j].x==10&&(A[i].x!=7)) swap(A[i],A[j]);*/
    sort(A+1,A+cnt+1);
    //rep(i,1,cnt) printf("%d %d\n",A[i].x,A[i].y);
    dfs(1);
    return 0;
}
View Code

T3:

 

恩让我回忆回忆2333

-------------------

似乎记得要二分答案,那就先二分答案吧。

考虑如何判定x是否可行,将|E|/|V|>k变形成|E|-k*|V|>0,发现这是个裸的最大权闭合子图。因为选中一条边能贡献1的权,但同时要依赖于两个端点也必须选,而这两个端点的贡献每个都是-k。那么跑一边最大流,算一下是否为m即可。

等等,这道题要你输出分数啊!那么最后再计算一下最优解,在网络中找那些指向汇点且被割断的边,这些边的另一端就是选择的点。

注意特判m=0

#include<cstdio>
#include<cstring>
#include<cctype>
#include<queue>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    char ch=getchar();int x=0,f=1;
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
const int maxn=2010;
const int maxm=50100;
const double eps=1e-5;
int n,m,u[5010],v[5010],A[60],is[60],cnt,ans;
struct Dinic {
    int n,m,s,t;
    int vis[maxn],cur[maxn],d[maxn],first[maxn],next[maxm];
    struct Edge {int from,to;double flow;}edges[maxm];
    void init(int n) {
         this->n=n;m=0;
         fill(first+1,first+n+1,-1);
    } 
    void AddEdge(int u,int v,double cap) {
         edges[m]=(Edge){u,v,cap};next[m]=first[u];first[u]=m++;
         edges[m]=(Edge){v,u,0.0};next[m]=first[v];first[v]=m++;     
    }
    int BFS() {
        fill(vis+1,vis+n+1,0);
        queue<int> q;q.push(s);d[s]=0;vis[s]=1;
        while(!q.empty()) {
            int x=q.front();q.pop();cur[x]=first[x];
            ren {
                Edge& e=edges[i];
                if(!vis[e.to]&&e.flow>eps) {
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }              
        }
        return vis[t];
    }
    double DFS(int x,double a) {
        if(x==t||a<eps) return a;
        double flow=0.0,f;
        for(int& i=cur[x];i!=-1;i=next[i]) {
            Edge& e=edges[i];
            if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.flow)))>eps) {
                e.flow-=f;edges[i^1].flow+=f;
                flow+=f;a-=f;if(a<eps) break;
            } 
        }
        return flow;
    }
    double MaxFlow(int s,int t) {
        double ans=0.0;this->s=s;this->t=t;
        while(BFS()) ans+=DFS(s,1e50);  
        return ans;     
    }
    void solve() {
        rep(0,m-1) if(edges[i].to==t&&edges[i].flow<eps) A[++cnt]=edges[i].from;  
    }
}sol;
int check(double mid) {
    sol.init(n+m+2);
    int s=n+m+1,t=n+m+2;
    rep(1,m) sol.AddEdge(s,i,1.0),sol.AddEdge(i,u[i]+m,1e50),sol.AddEdge(i,v[i]+m,1e50);
    rep(1,n) sol.AddEdge(i+m,t,mid);
    return m-sol.MaxFlow(s,t)>eps;
}
int gcd(int a,int b) {return !b?a:gcd(b,a%b);}
int main() {
    freopen("density.in","r",stdin);
    freopen("density.out","w",stdout);
    n=read(),m=read();
    if(!m) {puts("0/1");return 0;}
    rep(1,m) u[i]=read(),v[i]=read();
    double l=0.0,r=m;
    while(r-l>eps) {
        double mid=(l+r)*0.5;
        if(check(mid)) l=mid;
        else r=mid;            
    }
    check(l);sol.solve();
    rep(1,cnt) is[A[i]-m]=1;
    rep(1,m) if(is[u[i]]&&is[v[i]]) ans++;
    printf("%d/%d\n",ans/gcd(ans,cnt),cnt/gcd(ans,cnt));
    return 0;
}
View Code

 交上去WA了一个点,FHQ带大家测了半天,最后发现最小割不唯一会WA。于是暴力枚举分子分母的过了23333

posted @ 2015-07-10 13:02  wzj_is_a_juruo  阅读(319)  评论(0编辑  收藏  举报