• BZOJ 几道水题 2014-4-22


    BZOJ P1088  [SCOI2005]扫雷Mine  

    可以发现确定前两格的个数后,后面的格子都会被自动确定,所以枚举前两格个数再判定一下即可

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    using namespace std;
    const int N=10500;
    int n,m,k,ans;
    int a[N],b[N];   
    bool check()
      { for (int i=2;i<=n;i++)
        b[i+1]=a[i]-b[i]-b[i-1]; 
        if (b[n+1]) return 0; 
        return 1;     
       }
    int main()
      {  scanf("%d",&n);
         for (int i=1;i<=n;i++) scanf("%d",&a[i]);  
         if (a[1]>2) {printf("0
    "); return 0;}
         for (int i=0;i<=a[1];i++)
            { memset(b,0,sizeof(b));  
              b[1]=i; b[2]=a[1]-i;  
              if (check()) ans++;}
         printf("%d",ans);  
        }
    View Code

    BZOJ P2561  最小生成树

    给你一个图,问你最小删掉几条边使边(u,v)能出现在最大生成树和最小生成树上

    回忆Kruskal算法,某一条边能放入最小生成树只有比这条边小的边不能把(u,v)连接到一个连通块内

    跑一边u到v的最小割即可

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=20100,M=1001000,inf=~0U>>1;
    int fl[M],no[1001000],next[M],op[M],tot=0;
    int a[M],b[M],c[M],num[N],d[N],base[N],S,T,t,n,m;  
    int add(int x,int y)
      { no[++tot]=y; fl[tot]=1;
        next[tot]=base[x]; op[tot]=tot+1;
        base[x]=tot;
        no[++tot]=x; fl[tot]=0;
        next[tot]=base[y]; op[tot]=tot-1;    
        base[y]=tot;  
        } 
    int sap(int u,int flow)
    { if (u==T) return flow;      
      int tmp,now=0;
      for (int i=base[u];i;i=next[i])
       {  int x=no[i];   
          if (fl[i]<=0||d[u]!=d[x]+1) continue;
          tmp=sap(x,min(flow-now,fl[i]));
          now+=tmp; fl[i]-=tmp; fl[op[i]]+=tmp;   
          if (now==flow) return now; 
          }
      if (d[S]>=n) return now;
      num[d[u]]--; if (!num[d[u]]) d[S]=n;
      num[++d[u]]++;  return now;
       }
        
    int main()
      {  scanf("%d%d",&n,&m);
         for (int i=1;i<=m;i++)
         scanf("%d%d%d",&a[i],&b[i],&c[i]);
         scanf("%d%d%d",&S,&T,&t);
         for (int i=1;i<=m;i++)  
         if (c[i]<t) add(a[i],b[i]),add(b[i],a[i]);
         num[0]=n;  int ans=0;
         while (d[S]<n) ans+=sap(S,inf);
         memset(base,0,sizeof(base)); tot=0;   
         for (int i=1;i<=m;i++)  
         if (c[i]>t) add(a[i],b[i]),add(b[i],a[i]);
         memset(num,0,sizeof(num));  num[0]=n; 
         memset(d,0,sizeof(d));   
         while (d[S]<n) ans+=sap(S,inf);
         printf("%d
    ",ans);   
         }
    View Code

    BZOJ  P1296  [SCOI2009]粉刷匠

    很显然对每一行单独处理后,得到这一行分成K段的最大收益后,这就是一个分组背包

    对每一行,状态表示为Dp[i][k][w],表示已分成K段,目前染成颜色W的最大收益

    DP[i][k][w]=max(Dp[i-1][k][w],Dp[i-1][k-1][!w])+(w==col[i])

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <algorithm>
    using namespace std;
    int dp[61][61][4],tmp[2501],f[2510];
    int ans=0,n,m,t,c[90];
    string s;  
    int predo()
      {   //dp[1][1][c[1]]=1;
         for (int i=1;i<=m;i++)
         for (int j=1;j<=m;j++)
         { int w=c[i];
           dp[i][j][w]=max(dp[i-1][j-1][!w],dp[i-1][j][w])+1;
           dp[i][j][!w]=max(dp[i-1][j][!w],dp[i-1][j-1][w]);
           tmp[j]=max(tmp[j],dp[i][j][w]);
           tmp[j]=max(tmp[j],dp[i][j][!w]);   
           }
         }
    int dpit()
      { for (int i=t;i;i--)
         for (int j=1;j<=m;j++)
          if (tmp[j]>0&&i>=j)
         f[i]=max(f[i],f[i-j]+tmp[j]),ans=max(ans,f[i]);
       } 
    int main()
      {  //freopen("1.in","r",stdin);
         scanf("%d%d%d",&n,&m,&t);
         for (int i=1;i<=n;i++)    
           { cin>>s; 
             memset(dp,0,sizeof(dp));
             memset(tmp,0,sizeof(tmp)); 
             for (int j=0;j<m;j++)
               if (s[j]=='0') c[j+1]=0;else c[j+1]=1;    
              predo();
              dpit();  
              }
         printf("%d
    ",ans);
         return 0;  
        } 
    View Code

    BZOJ P1787 [Ahoi2008]Meet 紧急集合

    树上到两点距离和最短的点一定在两点之间的路径上,三个点两两之间路径必然有一个交点(不然就是个环了)

    用倍增就求出三个LCA再判定一下即可。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    const int N=500010,k=30,inf=~0U>>1;
    int f[N],dp[N][k+1],d[N];
    bool vis[N]; int n,m,x,y,z,maxx,ans,tot;  
    int base[N],next[N*2],now[N*2];  
    int add(int x,int y)
      {  now[++tot]=y; 
         next[tot]=base[x];
         base[x]=tot;   
         } 
      
    int dfs(int u)
      {  vis[u]=1;  
         for (int i=base[u];i;i=next[i])
           if (!vis[now[i]])  
            { int x=now[i]; 
              dp[x][0]=u; d[x]=d[u]+1;   
              dfs(x);  
              }
         }
      
    int lca(int x,int y)
      { if (x==y) return x;
        if (d[x]<d[y]) swap(x,y);   
        for (int i=k;i>=0;i--)
        if (d[dp[x][i]]>=d[y]) x=dp[x][i];
        if (x==y) return x;
        for (int i=k;i>=0;i--)
        if (dp[x][i]!=dp[y][i])
         x=dp[x][i],y=dp[y][i];
        return dp[x][0];   
        }
      
    int abs(int x){if (x<0) return -x; return x; }
    int dist(int x,int y)
      {  int u=lca(x,y);
         return d[x]-d[u]+d[y]-d[u];}
    int main()
      {  //freopen("1.in","r",stdin);
         scanf("%d%d",&n,&m);
         for (int i=1;i<=n-1;i++)  
           {scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);}
        memset(vis,0,sizeof(vis));
        d[0]=-1;  dfs(1);
        for (int i=1;i<=k;i++)
            for (int j=1;j<=n;j++)
              dp[j][i]=dp[dp[j][i-1]][i-1];
        while (m--) {
            int a,b,c,ans1=inf,ans0,l,x;
            scanf("%d%d%d",&a,&b,&c);
            l=lca(a,b);
            x=d[a]-d[l]+d[b]-d[l]+dist(l,c);
            if (x<ans1||(x==ans1&&l<ans0)) {
                ans1=x,ans0=l;
            }
            l=lca(b,c);
            x=d[b]-d[l]+d[c]-d[l]+dist(l,a);
            if (x<ans1||(x==ans1&&l<ans0)) {
                ans1=x,ans0=l;
            }
            l=lca(a,c);
            x=d[a]-d[l]+d[c]-d[l]+dist(l,b);
            if (x<ans1||(x==ans1&&l<ans0)) {
                ans1=x,ans0=l;
            }
            printf("%d %d
    ",ans0,ans1);
        }
       }
    View Code

    BZOJ P2516 [NOI2003]Editor

    为Rope打造的题

    #include <cstdio>
    #include <ext/rope>
    #include <iostream>
    #include <cstring>
    #include <string>
    using namespace std;
    using namespace __gnu_cxx;
    int n,now,k;
    char s[2500005],s1[50];
    crope R;
    int main()
     {  //freopen("1.in","r",stdin);
        scanf("%d",&n); 
        while (n--)
         {  scanf("%s",s1);
            if (s1[0]=='M') scanf("%d",&now);
            if (s1[0]=='P') now--;
            if (s1[0]=='N') now++;
            if (s1[0]=='I')
            {scanf("%d%*c",&k);
            for (int i=0;i<k;i++) do
                {
                    scanf("%c",&s[i]);
                }while(s[i]=='
    ');
            s[k]=0;
            R.insert(now,s);}
            if (s1[0]=='D') 
            scanf("%d",&k),R.erase(now,k);
            if (s1[0]=='G')
            scanf("%d",&k),R.copy(now,k,s),s[k]=0,puts(s);
         }
       return 0;
      }
    View Code

    BZOJ P1293 [SCOI2009]生日礼物

    对于每个确定的右端点,它左端点的最大值就是所有颜色最后一次出现位置的最小值

    O(N*K)可以水过

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N=2001000;
    long long M=2147483646;
    typedef struct seg{int co,x;}seg;
    int n,m,k,tot=0;   
    seg a[N]; int pre[70];
    bool cmp(seg x,seg y)
      {return x.x<y.x;}
     
    int scan(int &x){ char c;
        while(c=getchar(),c<'0'||c>'9');x=c-'0';
        while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
        }
     
    int main()
      {  
         scanf("%d",&n); scanf("%d",&m);  
         for (int i=1;i<=m;i++) pre[i]=0;
         for (int i=1;i<=m;i++)
            {  scanf("%d",&k);
               while (k--) scanf("%d",&a[++tot].x),a[tot].co=i;   
               } 
         sort(a+1,a+tot+1,cmp);
         long long ans=M;
         for (int i=1;i<=n;i++)
           {  int minn=M;
              pre[a[i].co]=a[i].x;
              for (int j=1;j<=m;j++)
                minn=min(pre[j],minn);
              if (minn==0) continue;
              if (a[i].x-minn<ans) ans=a[i].x-minn; 
              }
         printf("%d
    ",ans);
         return 0;
       }
    View Code

    BZOJ P1051  [HAOI2006]受欢迎的牛

    tarjan算法即可,缩点后找出度为0并唯一的强连通分量的大小输出

     
    #include <cstdio>
    #include <iostream>
    #include <stack>
    #include <algorithm>
    #include <vector>
    using namespace std;
    stack<int>S;
    const int maxn=50101;
    int n,m,tot,a[maxn],b[maxn],dfn[maxn];  
    int out[maxn],size[maxn],low[maxn],f[maxn]; 
    bool vis[maxn]; int num=0;
    vector<int>G[maxn]; 
    int tarjan(int u)
      {   dfn[u]=low[u]=++tot;
          S.push(u); vis[u]=1;  
          for (int i=0;i<G[u].size();i++)
            {  int x=G[u][i];
               if (vis[x]) low[u]=min(low[u],dfn[x]);
               else tarjan(x),low[u]=min(low[u],low[x]);
               }
          if (dfn[u]!=low[u]) return 0; 
          num++;     
          while (S.top()!=u) f[S.top()]=num,size[num]++,S.pop();
           S.pop();  f[u]=num; size[num]++;  
          }  
    int main()
      {  //freopen("1.in","r",stdin);
         scanf("%d%d",&n,&m);  
         for (int i=1;i<=m;i++)
         {scanf("%d%d",&a[i],&b[i]);
          G[a[i]].push_back(b[i]);  
            }
         for (int i=1;i<=n;i++)  
          if (!vis[i]) tarjan(i);
         for (int i=1;i<=m;i++)  
          if (f[a[i]]!=f[b[i]]) 
            out[f[a[i]]]++;
          int cnt=0,k=0;  
          for (int i=1;i<=num;i++) 
            if (!out[i])  cnt+=size[i],k++;
          if (k==1)
          printf("%d
    ",cnt); else printf("0
    "); 
         }
    View Code

    BZOJ P1015 [JSOI2008]星球大战starwar

    离线并查集倒序加边即可

    #include <cstdio>
    #include <iostream>
    #include <cstdio>
    #include <vector>
    const int maxn=400010;
    using namespace std;
    bool bo[maxn]; int lis[maxn],f[maxn],ans[maxn];
    vector<int>G[maxn];
    int sf(int x)
       {  if (f[x]==x) return x;
          return f[x]=sf(f[x]); } 
    int bfs(int x)
      {  int ans=0;  
         for (int i=0;i<G[x].size();i++)
           { int y=G[x][i]; if (bo[y]) continue;
             y=sf(y);  int fx=sf(x);
             if (y!=fx) f[y]=fx,ans++;
             } 
           return ans;
          }
    int main()
     {  //freopen("1.in","r",stdin);  
        int n,m,k; int x,y;
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++) 
        {scanf("%d%d",&x,&y),x++,y++;
         G[x].push_back(y),G[y].push_back(x);}
        scanf("%d",&k);
        for (int i=1;i<=n;i++) f[i]=i;
        for (int i=1;i<=k;i++)   
        scanf("%d",&lis[i]),bo[++lis[i]]=1;
        for (int i=1;i<=n;i++)    
        if (!bo[i]) bfs(i);  
        for (int i=1;i<=n;i++) if (sf(i)==i) ans[k]++;
        ans[k]-=k; 
        for (int i=k;i;i--)
           {  int x=lis[i]; bo[x]=0;  
              ans[i-1]=ans[i]-bfs(x)+1; 
             }
        for (int i=0;i<=k;i++) 
         printf("%d
    ",ans[i]);
    }
    View Code

    BZOJ P2875   [Noi2012]随机数生成器

    矩阵乘法模板题

    #include <cstdio>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    typedef struct matrix{ll a[4][4];}matrix;
    ll x0,m,c,a,n,g;
    matrix ma,mb,tmp;
    ll multi(ll x,ll y,ll m)
      { ll tmp=x; ll ans=0;
        while (y)
        { if (y&1) ans=(ans+tmp)%m;
          tmp=(tmp+tmp)%m; y/=2;}
         return ans%m;
       }
     
    matrix mult(matrix ma,matrix mb,ll n,ll r,ll c,ll m)
       {   matrix mc=tmp;
           for (int i=1;i<=r;i++)  
             for (int j=1;j<=c;j++)
              for (int k=1;k<=n;k++)
             { mc.a[i][j]=(mc.a[i][j]+multi(ma.a[i][k],mb.a[k][j],m))%m;}
             return mc;
           }
     
    matrix power(matrix ma,ll r,ll c,ll m,ll b)
       {  if (b==1) return ma;
          matrix mc=power(ma,r,c,m,b/2);   
          mc=mult(mc,mc,r,c,r,m);
          if (b&1) mc=mult(mc,ma,r,c,r,m);
          return mc;
          } 
           
    int main()
      {  //freopen("1.in","r",stdin);
         cin>>m>>a>>c>>x0>>n>>g;
         ma.a[1][1]=a; ma.a[1][2]=1;
         ma.a[2][1]=0; ma.a[2][2]=1;
         mb.a[1][1]=x0; mb.a[2][1]=c;
         ma=power(ma,2,2,m,n);
         mb=mult(ma,mb,2,2,1,m);
         cout<<mb.a[1][1]%g;
      }
    View Code

    BZOJ P2456  mode

    看起来很水但要求不能用数组,采用抵消掉思想

    每进一个数,如果之前有没被抵消掉数就抵消一次

    如果出项一半以上,它一定不能被抵消完,剩下那个数就是要找到数

    #include <cstdio>
    using namespace std;
    int n,tot,now,tmp;
    int main()
      {   scanf("%d",&n);
          for (int i=1;i<=n;i++)
            {  scanf("%d",&tmp);
               if (tot==0) now=tmp;
               if (now==tmp) tot++;
               else tot--;
               }
         printf("%d
    ",now);}
    View Code

    BZOJ P2190 [SDOI2008]仪仗队

    一个点到原点的直线上有整点,那么这两个数的gcd就不是1

    算一下(1~N-1)中的欧拉函数和就可以了

    #include <cstdio>
    #include <iostream>
    using namespace std;
    const int maxn=40010;
    long long phi[maxn];
    bool b[maxn]; int n;
    int main()
      {  scanf("%d",&n);    
         long long ans=0;
         for (int i=1;i<=n;i++) phi[i]=i;
         for (int i=2;i<=n;i++) 
           if (!b[i])
            {  phi[i]--;
               for (int j=2;j*i<=n;j++)
                 phi[i*j]=(phi[i*j]/i)*(i-1),b[i*j]=1;
               }
        for (int i=1;i<=n-1;i++)  ans+=phi[i]*2;
        //if (n<2) printf("0
    "); 
         printf("%lld
    ",ans+1);
       }
    View Code

    BZOJ  P2818  Gcd

    欧拉函数和.....

     
    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const int maxn=12000000;
    ll phi[maxn]; bool b[maxn]; int prim[maxn];
    int main()
      {  int n;  int tot=0;
         scanf("%d",&n);
         for (int i=2;i<=n;i++) phi[i]=i;
         for (int i=2;i<=n;i++) 
           if (!b[i])
           { prim[++tot]=i; phi[i]=i-1;  
             for (int j=2;j*i<=n;j++)
               b[i*j]=1,phi[i*j]=(phi[i*j]/i)*(i-1);
             }  
         for (int i=2;i<=n;i++) 
            phi[i]=phi[i]+phi[i-1]; ll ans=0;   
         for (int i=1;i<=tot;i++) ans+=2*phi[n/prim[i]]+1;
         printf("%lld
    ",ans);
         }
    View Code

    BZOJ P1202 [HNOI2005]狡猾的商人

    差分约束判定即可

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int maxn=3010;
    typedef struct seg{int x,next,f;}seg;
    seg v[maxn]; int base[maxn],cnt[maxn],d[maxn];
    int n,m,t,x,y,z,tot=0; bool vis[maxn];
    int add(int x,int y,int z)
     { v[++tot].x=y; v[tot].f=z; 
       v[tot].next=base[x]; base[x]=tot;
       }
    queue<int>Q;
    bool spfa()
     {  while (!Q.empty()) Q.pop();
        for (int i=0;i<=n;i++) 
          Q.push(i),vis[i]=1,d[i]=cnt[i]=0;
        while (!Q.empty())
          {  int u=Q.front(); Q.pop(); vis[u]=0;
             for (int i=base[u];i;i=v[i].next)
              {  int x=v[i].x; 
                 if (d[x]<=d[u]+v[i].f) continue;
                 if (++cnt[x]>n) return 0;
                 d[x]=d[u]+v[i].f; 
                 if (!vis[x]) vis[x]=1,Q.push(x);
                 }
               }  return 1;
          }
      
    int main()
      { //freopen("1.in","r",stdin);
        scanf("%d",&t);
        while (t--) 
         {  scanf("%d%d",&n,&m);
            tot=0; memset(base,0,sizeof(base));
            while (m--)
              { scanf("%d%d%d",&x,&y,&z); 
                add(x-1,y,z); add(y,x-1,-z);  
                 }
             if (spfa())puts("true");else puts("false");
           }
         }
    
    View Code

    BZOJ P1491 [NOI2007]社交网络

    floyed用乘法原理计算最短路的数量

    再一遍floyed查看中转点是否能在最短路径上

    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    const int maxn=2560;
    int n,m,r,c;      
    int g[101][101]; 
    int pos[maxn]; bool vis[maxn];  
    vector<int>G[maxn*500];
    int dx[8],dy[8];
    bool dfs(int x)
      { for (int i=0;i<G[x].size();i++)
         { int y=G[x][i]; if (vis[y]) continue;vis[y]=1;
           if (!pos[y]||dfs(pos[y])) {pos[y]=x; return 1;}   
            }
         return 0;
       }
    int main()
      {   //freopen("1.in","r",stdin);
          scanf("%d%d%d%d",&n,&m,&r,&c); 
          int tot=0;    char s[maxn];
          for (int i=1;i<=n;i++)
           { scanf("%s",&s);
             for (int j=1;j<=m;j++) 
             if (s[j-1]=='.') tot++,g[i][j]=tot;
              }
         dx[0]=r; dx[1]=r; dx[2]=c; dx[3]=c; 
         dy[0]=c; dy[1]=-c; dy[2]=-r; dy[3]=r; 
         for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
            if (g[i][j]) for (int k=0;k<=3;k++) 
              {   int x=i+dx[k],y=j+dy[k];
                  if (x>0&&x<=n&&y>0&&y<=m) 
                  if (g[x][y]) G[g[i][j]].push_back(g[x][y]);
                   }  int ans=0;  //printf("%d",tot);
            for (int i=1;i<=tot;i++)  
            {memset(vis,0,sizeof(vis));if (dfs(i)) ans++;}
          printf("%d
    ",tot-ans);
      
      }
    View Code
  • 相关阅读:
    yum与rpm常用命令
    centos7更改时区,同步时间
    剑指Offer45:扑克牌顺子(java)
    剑指Offer44:翻转单词顺序列(java)
    剑指Offer43:左旋转字符串(Java)
    剑指Offer42:和为S的两个数字(java)
    剑指Offer41:和为S的连续正数序列(Java)
    剑指Offer39:平衡二叉树(Java)
    剑指Offer40:数组中只出现一次的数字(Java)
    剑指Offer38:二叉树的深度(Java)
  • 原文地址:https://www.cnblogs.com/williamchenwl/p/3681706.html
Copyright © 2020-2023  润新知