• bzoj1000~1025


    以后还是这样 25道题一起发 看着爽

    noip失利之后发粪涂墙 刷了一波bzoj

    题解:

    bzoj1000 A+B问题

    这题不同的人有不同的写法,我写了个线段树套Treap,应该还是挺简单的

    但是看别的大神的代码跑的飞快就粘过来吧   这题竟然不用树套树,太强了

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int main()
    {
        int a,b;
        cin>>a>>b;
        cout<<a+b;
        return 0;
    } 
    View Code

    bzoj1001 狼抓兔子

    平面图最小割

    建图方式比较奇怪,注意一下就可以了

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int n,m;
    int ne;
    struct data{int to,next,v;}e[6000001];
    int head[1000001];
    int h[1000001],q[1000001],ans;
    void insert(int u,int v,int w)
    {
        ne++;
        e[ne].to=v;
        e[ne].v=w;
        e[ne].next=head[u];
        head[u]=ne;
    }
    bool bfs()
    {
        int now,i;
        memset(h,-1,sizeof(h));
        int t=0,w=1;
        q[t]=1;h[1]=0;
        while(t<w)
        {   
            now=q[t];t++;
            i=head[now];
            while(i)
            {
                if(e[i].v&&h[e[i].to]<0)
                {
                    q[w++]=e[i].to;
                    h[e[i].to]=h[now]+1;                 
                }
                i=e[i].next;
            }
        }
        if(h[n*m]==-1)return 0;
        return 1;
    }
    int dfs(int x,int f)
    {
        if(x==n*m)return f;
        int i=head[x];
        int w,used=0;
        while(i)
        {
            if(e[i].v&&h[e[i].to]==h[x]+1)
            {
                w=f-used;
                w=dfs(e[i].to,min(w,e[i].v));
                e[i].v-=w;
                e[i+1].v+=w;
                used+=w;
                if(used==f)return f;
            }
            i=e[i].next;
        }
        if(!used)h[x]=-1;
        return used;
    }
    void dinic()
    {
        while(bfs())ans+=dfs(1,0x7fffffff);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int x;
        for(int i=1;i<=n;i++)
            for(int j=1;j<m;j++)
            {
                scanf("%d",&x);
                insert(m*(i-1)+j,m*(i-1)+j+1,x);
                insert(m*(i-1)+j+1,m*(i-1)+j,x);
            }
        for(int i=1;i<n;i++)
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&x);
                insert(m*(i-1)+j,m*(i)+j,x);
                insert(m*(i)+j,m*(i-1)+j,x);
            }
        for(int i=1;i<n;i++)
            for(int j=1;j<m;j++)
            {
                scanf("%d",&x);
                insert(m*(i-1)+j,m*(i)+j+1,x);
                insert(m*(i)+j+1,m*(i-1)+j,x);
            }
        dinic();
        printf("%d",ans);
        return 0;
    }
    网络流
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<set>
    #include<map>
    #include<vector>
    #include<stack>
    #include<queue>
    #define ll long long
    #define inf 2147383611
    #define MAXN 1001001
    #define MOD
    using namespace std;
    inline int read()
    {
        int x=0,f=1;
        char ch;ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m,x,ans,lim;
    int to[MAXN*6+2010],val[MAXN*6+4010],first[MAXN*2],next[MAXN*6+4010],cnt;
    int dis[MAXN*2];
    bool vis[MAXN*2];
    void add(int u,int v,int d) {next[++cnt]=first[u],first[u]=cnt,val[cnt]=d,to[cnt]=v;}
    void spfa()
    {
        memset(dis,127,sizeof(dis));
        queue <int> q;
        q.push(0);dis[0]=0,vis[0]=1;
        while(!q.empty())
        {
            int k=q.front();
            q.pop();
            vis[k]=0;
            for(int i=first[k];i;i=next[i])
                if(dis[to[i]]>dis[k]+val[i])
                {
                    dis[to[i]]=dis[k]+val[i];
                    if(!vis[to[i]]) {q.push(to[i]);vis[to[i]]=1;}
                }
        }
        printf("%d",dis[lim+1]);
    }
    int main()
    {
        n=read(),m=read();
        ans=inf,lim=2*(m-1)*(n-1);
        if(n==1)
        {
            for(int i=1;i<m;i++) {x=read(),ans=min(ans,x);}
            printf("%d",ans);return 0;
        }
        if(m==1)
        {
            for(int i=1;i<n;i++) {x=read(),ans=min(ans,x);}
            printf("%d",ans);return 0;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<m;j++)
            {
                x=read();
                if(i==1) {add(lim+1,j*2,x);add(j*2,lim+1,x);continue;}
                if(i==n) {add(0,(n-2)*(m-1)*2+j*2-1,x);add((n-2)*(m-1)*2+j*2-1,0,x);continue;}
                add((i-1)*(m-1)*2+j*2,(i-2)*(m-1)*2+j*2-1,x);add((i-2)*(m-1)*2+j*2-1,(i-1)*(m-1)*2+j*2,x);
            }
        }
        for(int i=1;i<n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                x=read();
                if(j==1) {add(0,(m-1)*(i-1)*2+1,x);add(2*(m-1)*(i-1)+1,0,x);continue;}
                if(j==m) {add(lim+1,i*(m-1)*2,x);add(i*(m-1)*2,lim+1,x);continue;}
                add((i-1)*(m-1)*2+2*(j-1),(i-1)*(m-1)*2+2*j-1,x);add((i-1)*(m-1)*2+2*j-1,(i-1)*(m-1)*2+2*(j-1),x);
            }
        }
        for(int i=1;i<n;i++)
        {
            for(int j=1;j<m;j++)
            {
                x=read();
                add((i-1)*(m-1)*2+2*j,(i-1)*(m-1)*2+2*j-1,x);add((i-1)*(m-1)*2+2*j-1,(i-1)*(m-1)*2+2*j,x);
            }
        }
        spfa();
    }
    对偶图

    bzoj1002 轮状病毒

    这题当年应该没多少人严格论证并写出来正解,时至今日已成为一道高精度练习题

    网上严格论证。。。稀如凤毛麟角

    找规律+高精度

     
    #include<iostream>
    #include<cstdio>
    using namespace std;
    struct data{
           int a[101],len;
           };
    int n;
    data mul(data a,int k)
    {
        for(int i=1;i<=a.len;i++)
                a.a[i]*=k;
        for(int i=1;i<=a.len;i++)
        {
                a.a[i+1]+=a.a[i]/10;
                a.a[i]%=10;
                }
        if(a.a[a.len+1]!=0)a.len++;
        return a;
    } 
    data sub(data a,data b)
    {
        a.a[1]+=2;
        int j=1;
        while(a.a[j]>=10){a.a[j]%=10;a.a[j+1]++;j++;} 
        for(int i=1;i<=a.len;i++)
        {
               a.a[i]-=b.a[i];
               if(a.a[i]<0){a.a[i]+=10;a.a[i+1]--;}
        }
        while(a.a[a.len]==0)a.len--;
        return a;
    }
    int main()
    {
        data f[101];f[1].a[1]=1;f[2].a[1]=5;
        f[1].len=f[2].len=1;
        scanf("%d",&n);
        for(int i=3;i<=n;i++)
                f[i]=sub(mul(f[i-1],3),f[i-2]);
        for(int i=f[n].len;i>0;i--)
           printf("%d",f[n].a[i]);
        return 0;
    }
    View Code

    bzoj1003 物流运输

    spfa+dp,dp[i][j]表示从第i天到第j天表示从第i天到第j天都能走的1~n最短路长度

    f[i]表示前i天最小费用,初始化f[i]=dp[1][i]

    递推式为f[i]=min{f[j]+dp[j+1][i]+k}(i>=2,j∈[1,i-1])

    bzoj1004 Cards

    置换群  Burnside定理  背包

    反正就是个狂拽酷炫吊炸天的背包

    具体可以看https://www.cnblogs.com/JoeFan/p/4299628.html这篇文章讲的挺好的

    心疼当年考的小伙伴

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define N 110
    using namespace std;
    typedef long long ll;
    int sr,sb,sg,n,m,mod;
    int cir[N][N],v[N],size[N];
    ll f[N][N][N],ans;
    int calc(int x)
    {
        int cnt=0;
        memset(v,0,sizeof(v));
        memset(size,0,sizeof(size));
        for(int i=1;i<=n;i++)
        {
            if(v[i])continue;
            int p=cir[x][i];
            cnt++;
            while(!v[p])v[p]=1,size[cnt]++,p=cir[x][p];
        }
        memset(f,0,sizeof(f));
        f[0][0][0]=1;
        for(int i=1;i<=cnt;i++)
            for(int j=sr;j>=0;j--)
                for(int k=sb;k>=0;k--)
                    for(int l=sg;l>=0;l--)
                    {
                        if(j>=size[i])f[j][k][l]=(f[j][k][l]+f[j-size[i]][k][l])%mod;
                        if(k>=size[i])f[j][k][l]=(f[j][k][l]+f[j][k-size[i]][l])%mod;
                        if(l>=size[i])f[j][k][l]=(f[j][k][l]+f[j][k][l-size[i]])%mod;
                    }
        return f[sr][sb][sg];
    }
    ll quick_my(ll x,int y)
    {
        ll ret=1;
        while(y)
        {
            if(y&1)ret=(ret*x)%mod;
            x=(x*x)%mod;
            y>>=1;
        }
        return ret;
    }
    int main()
    {
        scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&mod);
        n=sr+sb+sg;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&cir[i][j]);
        m++;
        for(int i=1;i<=n;i++)cir[m][i]=i;
        ll ans=0;
        for(int i=1;i<=m;i++)ans=(ans+calc(i))%mod;
        ans=(ans*quick_my(m,mod-2))%mod;
        printf("%lld
    ",ans);
    }
    
    View Code

    bzoj1005 明明的烦恼

    又是一道结论题

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    struct bignum {
        int l, a[10000];
          
        bignum (int t) {
            l = 0; memset(a, 0, sizeof(0));
            while (t != 0) {
                a[++l] = t % 10000;
                t /= 10000;
            }
            if (l == 0) l = 1;
        }
          
        void mul(int k) {
            for (int i = 1; i <= l; i++)
                a[i] *= k;
            for (int i = 1; i <= l; i++)
                if (a[i] >= 10000) {
                    int t = i;
                    do {
                        a[t + 1] += a[t] / 10000;
                        a[t++] %= 10000;
                    } while (a[t] >= 10000);
                }
            while (a[l + 1] > 0) l++;
        }
          
        void print() {
            printf("%d", a[l]);
            for (int i = l - 1; i >= 1; i--)
                printf("%04d", a[i]);
            printf("
    ");
        }
    };
    int n, m = 0, tot = 0, d[1001], prime[1001], cnt[1001];
      
    bool judge(int k) {
        for (int i = 2; i <= sqrt(k); i++)
            if (k % i == 0) return false;
        return true;
    }
      
    void makelist(int n) {
        prime[0] = 0;
        for (int i = 2; i <= n; i++)
            if (judge(i)) prime[++prime[0]] = i;
    }
      
    void compute(int k, int t) {
        for (int i = 1; i <= prime[0] && prime[i] <= k; i++) {
            int x = 0, n = k, p = prime[i];
            while (n != 0) {
                x += n / p;
                n /= p;
            }
            cnt[i] += x * t;
        }
    }
      
    int main() {
        //freopen("input.txt", "r", stdin);
        //freopen("output.txt", "w", stdout);
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &d[i]);
            if (d[i] == -1) m++;
                else tot += d[i] - 1;
        }
          
        makelist(n);
        memset(cnt, 0, sizeof(cnt));
        compute(n - 2, 1);
        compute(n - 2 - tot, -1);
        for (int i = 1; i <= n; i++)
            if (d[i] != -1) compute(d[i] - 1, -1);
      
        bignum ans = 1;
        for (int i = 1; i <= prime[0]; i++)
            for (int j = 1; j <= cnt[i]; j++)
                ans.mul(prime[i]);
        for (int i = 1; i <= n - 2 - tot; i++)
            ans.mul(m);
        ans.print();
        return 0;
    }
    代码

    prufer序列的相关知识可以见https://www.cnblogs.com/CSU3901130321/p/4898261.html这篇博客

    bzoj1006 神奇的国度

    简单弦图的染色

    可以见CDQ的论文

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cstring>
    #define inf 0x7fffffff
    #define ll long long
    using namespace std;
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m,cnt,ans;
    int head[10005],d[10005],q[10005],col[10005],hash[10005];
    bool vis[10005];
    struct data{int to,next;}e[2000005];
    void ins(int u,int v)
    {e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;}
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int u=read(),v=read();
            ins(u,v);ins(v,u);
        }
        for(int i=n;i;i--)
        {
            int t=0;
            for(int j=1;j<=n;j++)
            {
                if(!vis[j]&&d[j]>=d[t])t=j;
            }
            vis[t]=1;q[i]=t;
            for(int j=head[t];j;j=e[j].next)
                d[e[j].to]++;
        }
        for(int i=n;i>0;i--)
        {
            int t=q[i];  
            for(int j=head[t];j;j=e[j].next)hash[col[e[j].to]]=i;
            int j;
            for(j=1;;j++)if(hash[j]!=i)break;
            col[t]=j;
            if(j>ans)ans=j;
        }
        printf("%d",ans);
        return 0;
    }
    View Code

    bzoj1007 水平可见直线

    终于不是结论题了

    水题 离散化 单调栈 完事

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    using namespace std;
    const double eps=1e-7;
    struct Vec{double a,b;int rank;}lines[50010];
    Vec st[50010];int top;
    bool cmp1(Vec x,Vec y)
    {
        if(fabs(x.a-y.a)<eps)return x.b<y.b;
        return x.a<y.a;
    }
    int check[50010];
    double Sv(Vec a,Vec b){return (b.b-a.b)/(a.a-b.a);}
    void Push(Vec a)
    {
        while(top)
        {
            if(fabs(st[top].a-a.a)<eps)--top;
            else if(top>1 && Sv(a,st[top-1])<=Sv(st[top],st[top-1]))--top;
            else break;
        }
        st[++top]=a;
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){scanf("%lf%lf",&lines[i].a,&lines[i].b);lines[i].rank=i;}
        sort(lines+1,lines+n+1,cmp1);
        for(int i=1;i<=n;i++)Push(lines[i]);
        for(int i=1;i<=top;i++)check[st[i].rank]=1;
        for(int i=1;i<=n;i++)if(check[i])cout<<i<<" ";
        return 0;
    }
    View Code

    bzoj1008 越狱

    数学题  要时刻注意%还是不%,%完了是正的负的

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib> 
    #define mod 100003
    #define ll long long
    using namespace std;
    ll m,n;
    ll qpow(ll a,ll b)
    {
        ll c=1,d=a%mod;
        while (b>0)
        {
            if (b&1)
             c=(c%mod*d%mod)%mod;
            b>>=1;
            d=(d%mod*d%mod)%mod;
        }
        return c;
    }
    int main()
    {
        scanf("%lld%lld",&m,&n);
        long long ans=qpow(m,n);
        ans=ans-m*qpow(m-1,n-1)%mod;
        if (ans<0)   ans+=mod;
        printf("%lld",ans);
        return 0;
    }
    View Code

    bzoj1009 GT考试

    KMP+矩阵乘法加速DP

    递推式很好想

    设a[k][j]为k位后面加一个字母转移到j的方案数

    dp[i][j]=dp[i1][k]a[k][j](0<=k<=m1

    因为是线性的 可以矩阵优化

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #define ll long long
    int m,mod;
    using namespace std;
    struct mat  
    {  
        ll a[25][25];
        mat operator*(const mat &y)const
        {
            mat res;
            memset(res.a,0,sizeof(res.a));  
            for(int i=0;i<m;i++)  
                for(int j=0;j<m;j++)  
                    for(int k=0;k<m;k++)  
                    {  
                        res.a[i][j]+=a[i][k]*y.a[k][j];  
                        res.a[i][j]%=mod;
                    }  
            return res;  
        }
    }a,b;  
    mat ksm(mat A,int n)  
    {  
        mat res;  
        if(n==1) return A;  
        res=ksm(A,n/2);  
        res=res*res;
        if(n%2==1)res=res*A; 
        return res;  
    }  
    void mul(int a[25][25],int b[25][25],int ans[25][25])
    {
        int tmp[25][25];
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
            {
                tmp[i][j]=0;
                for(int k=0;k<m;k++)
                    tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
            }
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
                ans[i][j]=tmp[i][j];
    }
    int sum;
    char ch[30010];
    int nxt[30010];
    int main()
    {
        int n;
        scanf("%d%d%d",&n,&m,&mod);
        scanf("%s",ch+1);
        int j=0;
        for(int i=2;i<=m;i++)
        {
            for(;j>0 && ch[j+1]!=ch[i];j=nxt[j]);
            if(ch[j+1]==ch[i])j++;
            nxt[i]=j;
        }
        for(int i=0;i<m;i++)
           for(int j=0;j<=9;j++)
           {
                int t=i;
                for(;t>0&&ch[t+1]-'0'!=j;t=nxt[t]);
                if(ch[t+1]-'0'==j)t++;
                if(t!=m)b.a[t][i]=(b.a[t][i]+1)%mod;
           }
        for(int i=0;i<m;i++)a.a[i][i]=1;
        while(n)
        {
            if(n&1)a=a*b;
            b=b*b;
            n>>=1;
        }
        for(int i=0;i<m;i++)(sum+=a.a[i][0])%=mod;
        printf("%d",sum);
        return 0;
    }
    View Code

     bzoj1010 玩具装箱toy

    斜率优化

    dp[i]=min(dp[j]+(sum[i]-sum[j]+i-j-1-L)^2) (j<i)

    推一推 搞成令f[i]=sum[i]+i,c=1+l

    然后用一个单调队列维护下凸壳就好了

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<cstdlib>
    #define ll long long
    using namespace std;
    int n,L,l,r;
    int c[50005],q[50005];
    ll s[50005],f[50005];
    double slop(int j,int k){return (f[k]-f[j]+(s[k]+L)*(s[k]+L)-(s[j]+L)*(s[j]+L))/(2.0*(s[k]-s[j]));}
    int main()
    {
        scanf("%d%d",&n,&L);L++;
        for(int i=1;i<=n;i++)scanf("%d",&c[i]);
        for(int i=1;i<=n;i++)s[i]=s[i-1]+c[i];
        for(int i=1;i<=n;i++)s[i]+=i;
        l=1;r=0;q[++r]=0;
        for(int i=1;i<=n;i++)
        {
            while(l<r && slop(q[l],q[l+1])<=s[i])l++;
            int t=q[l];
            f[i]=f[t]+(s[i]-s[t]-L)*(s[i]-s[t]-L);
            while(l<r && slop(q[r],i)<slop(q[r-1],q[r]))r--;
            q[++r]=i;
        }
        printf("%lld
    ",f[n]);
        return 0;
    }
    View Code

    bzoj1011 遥远的行星

    puts("-nan");

    果然HNaNOI

    正经做也是可以的

    由于“误差不超过5%”

    当数据小于50时,暴力    大于50时,用到一些估算技巧

    没有做过这么奇怪的题呢

    #include <bits/stdc++.h>
    using namespace std;
    double m[100005], sum[100005];
    int main()
    {
        int n;
        double a, ans;
        scanf("%d%lf", &n, &a);
        for(int j = 1; j <= n; ++j)
        {
            int i = (int)(a * j + 1e-8);
            scanf("%lf", m + j);
            ans = 0;
            if(j <= 500)
                for(int k = 1; k <= i; ++k)
                    ans += m[k] * m[j] / (j - k);
            else
                ans = sum[i] * m[j] / (j - i / 2);
            printf("%f
    ", ans);
            sum[j] = sum[j - 1] + m[j];
        }
        return 0;
    }
    View Code

    bzoj1012  最大数

    单调队列,二分查找

    但其实单调栈也是可以的。。。

    看到网上一片线段树的时候我以为我做错了

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,m,last,mod;
    int q[200005],id[200005],head,tail;
    void add(int x)
    {
        while (q[tail]<=x && tail) tail--;
        q[++tail]=x;id[tail]=++n;
    }
    int query(int x)
    {
        int l=n-x+1;
        int k=lower_bound(id+head,id+tail+1,l)-id;
        return q[k];
    }
    int main()
    {
        scanf("%d%d",&m,&mod);
        char ch[2];
        int x;
        head=1;tail=0;
        while(m--)
        {
            scanf("%s%d",ch,&x);
            if(ch[0]=='A') add((x+last)%mod);
            else printf("%d
    ",last=query(x));  
        }
        return 0;
    }
    View Code

    bzoj1013 Sphere(名字太长辣)

    高斯消元法裸题

    但是推方程组用了我3张纸

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    using namespace std;
    #define zero 1e-6
    int n;
    double ans[15],a[15][15],d[15][15];
    void init() {
        cin>>n;
        for (int i=1; i<=n+1; i++)
            for (int j=1; j<=n; j++) cin>>d[i][j];
        for (int i=1; i<=n; i++) {
            for (int j=1; j<=n; j++)
                a[i][j] = 2 * (d[i+1][j]-d[i][j]),
                          a[i][n+1] += d[i+1][j] * d[i+1][j] - d[i][j] * d[i][j];
        }
        memset(ans,0,sizeof ans);
    }
     
    void gauss() {
        for (int i=1; i<n; i++) {
            if (fabs(a[i][i])<zero)
                for (int j=i+1; j<=n; j++)
                    if (abs(a[j][i])>zero) {
                        for (int k=1; k<=n+1; k++) swap(a[i][k],a[j][k]);
                        break;
                    }
            for (int j=i+1; j<=n; j++) {
                double x = a[j][i] / a[i][i];
                for (int k=i; k<=n+1; k++) a[j][k] -= a[i][k] * x;
            }
        }
        ans[n]=a[n][n+1]/a[n][n];
        for (int i=n-1; i; i--) {
            for (int j=i+1; j<=n; j++) a[i][n+1] -= ans[j]*a[i][j];
            ans[i] = a[i][n+1] / a[i][i];
        }
    }
     
    void print() {
        for (int i=1; i<n; i++) printf("%.3lf ",ans[i]);
        printf("%.3lf
    ",ans[n]);
    }
     
    int main() {
        init();
        gauss();
        print();
        return 0;
    }
    View Code

    bzoj1014 火星人

    Splay,我写了题解

    传送门:http://www.cnblogs.com/Kong-Ruo/p/7895957.html

    bzoj1015 星球大战

    并查集,操作离线

    不得不说脑洞挺大的

    将操作倒过来

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int fa[400010];
    inline int read()
    {
        int x=0;char ch=getchar();
        while(ch<'0'||ch>'9'){ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x;
    }
    int n,m;
    int u,v,atk[400010],d[400010],ans[400010],vis[400010];
    inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    int first[400010],to[400010],next[400010],cnt=1;
    void add(int u,int v){to[++cnt]=v;next[cnt]=first[u];first[u]=cnt;}
    int tmp;
    void destroy(int x)
    {
        int p=find(x),q;
        for(int i=first[x];i;i=next[i])
        {
            if(!vis[to[i]])continue;
            q=find(to[i]);
            if(p!=q){fa[q]=p;tmp--;}
        } 
    }
    int main()
    {
        n=read();m=read();
        for(int i=0;i<n;i++)fa[i]=i;
        for(int i=1;i<=m;i++){u=read(),v=read();add(u,v);add(v,u);}
        int k=read();
        for(int i=1;i<=k;i++){atk[i]=read();d[atk[i]]=1;}
        for(int i=0;i<n;i++)
        {
            if(!d[i])
            {
                tmp++;
                destroy(i);
                vis[i]=1;
            }
        }
        ans[k+1]=tmp;
        for(int i=k;i>0;i--)
        {
            tmp++;
            destroy(atk[i]);
            vis[atk[i]]=1;
            ans[i]=tmp;
        }
        for(int i=1;i<=k+1;i++)printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

    bzoj1016 最小生成树计数

    Kruskal+乘法原理

    另:千万不要一看到并查集就写路径压缩!!!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int mod=31011;
    int fa[105];
    struct edge{int x,y,v;}e[1005];
    struct EDG{int l,r,v;}a[1005];
    inline int read()
    {
        int x=0;char ch=getchar();
        while(ch<'0'||ch>'9'){ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x;
    }
    int n,m,cnt,cntt,ans,sum;
    bool cmp(edge a,edge b){return a.v<b.v;}
    inline int find(int x){return x==fa[x]?x:find(fa[x]);}   //这里不能路径压缩!!!WA了好几遍 
    void kruskal()
    {
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=m;i++)
        {
            if(e[i].v!=e[i-1].v){a[++cnt].l=i;a[cnt-1].r=i-1;}
            int p=find(e[i].x),q=find(e[i].y);
            if(p!=q){fa[p]=q;a[cnt].v++;cntt++;}
        }
        a[cnt].r=m;
    }
    void dfs(int x,int c,int k)
    {
         if(c==a[x].r+1)
         {
             if(k==a[x].v)sum++;
             return;
         }
         int p=find(e[c].x),q=find(e[c].y);
         if(p!=q)
         {
             fa[p]=q;
             dfs(x,c+1,k+1);
             fa[p]=p;fa[q]=q;
         }
         dfs(x,c+1,k);
    }
    void kkruskal()
    {
        for(int i=1;i<=n;i++)fa[i]=i;
        for(int i=1;i<=cnt;i++)
        {
            sum=0;
            dfs(i,a[i].l,0);
            ans=(ans*sum)%mod;
            for(int j=a[i].l;j<=a[i].r;j++)
            {
                int p=find(e[j].x),q=find(e[j].y);
                if(p!=q)fa[p]=q;
            }
        }
    }
    int main()
    {
        ans++;
        n=read();m=read();
        for(int i=1;i<=n;i++)fa[i]=i;
        for(int i=1;i<=m;i++)e[i].x=read(),e[i].y=read(),e[i].v=read();
        kruskal();
        if(cntt!=n-1){printf("0");return 0;}
        kkruskal();
        printf("%d",ans);
        return 0;
    }
    View Code

    bzoj1017 魔兽地图DotR

    斗地主加强版

    装备合成形成一个森林

    预处理出高级物品的力量,价格,购买上限

    用f[i][j][k]表示前i个物品 有j个用于合成 总花费为k时提供的力量最大值

    对于以a为根的子树枚举合成b个物品,再把剩下的钱买不用于合成的物品

    用ff[i][j]表示以a为根的子树里的前i个节点花费为j时可以获得的力量最大值

    再d一遍

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=10*x+f-'0';ch=getchar();}
        return x*f;
    }
    const int maxn=60;
    const int inf=2147483233;
    int dp[maxn][maxn*2][2050],c[maxn][maxn*40],f[maxn][maxn*40];
    int n,m,t;
    int lim[maxn],pri[maxn],p[maxn];
    int rd[maxn];
    struct EDG
    {
        int to,next,val;
    }e[maxn*maxn*40];
    int first[maxn],cnt;
    inline void add(int u,int v,int w)
    {
        e[++cnt].to=v;
        e[cnt].next=first[u];
        e[cnt].val=w;
        first[u]=cnt;
        rd[v]++;
    }
    char ch[5];
    void dfs(int x)
    {
        if(!first[x])
        {
            lim[x]=min(lim[x],m/pri[x]);
            for(int i=0;i<=lim[x];i++)
                for(int j=i;j<=lim[x];j++)
                    dp[x][i][j*pri[x]]=(j-i)*p[x];
            return;
        }
        lim[x]=2147483233;
        for(int i=first[x];i;i=e[i].next)
        {
            dfs(e[i].to);
            lim[x]=min(lim[x],lim[e[i].to]/e[i].val);
            pri[x]+=e[i].val*pri[e[i].to];
        }
        lim[x]=min(lim[x],m/pri[x]);
        memset(c,-0x3f3f3f3f,sizeof(c));
        c[0][0]=0;
        for(int i=lim[x];i>=0;i--)
        {
            int cc=0;
            for(int j=first[x];j;j=e[j].next)
            {
                cc++;
                for(int k=0;k<=m;k++)
                    for(int l=0;l<=k;l++)
                        c[cc][k]=max(c[cc][k],c[cc-1][k-l]+dp[e[j].to][i*e[j].val][l]);
            }
            for(int j=0;j<=i;j++)
                for(int k=0;k<=m;k++)
                    dp[x][j][k]=max(dp[x][j][k],c[cc][k]+p[x]*(i-j));
        }
         
    }
    int main()
    {
        memset(dp,-0x3f3f3f3f,sizeof(dp));
        scanf("%d%d",&n,&m);
        int x,y,uu;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&p[i]);
            scanf("%s",ch);
            if(ch[0]=='B')scanf("%d%d",&pri[i],&lim[i]);
            else
            {
                scanf("%d",&x);
                for(int j=1;j<=x;j++)
                {
                    scanf("%d%d",&y,&uu);
                    add(i,y,uu);
                }
            }
        }
        for(int z=1;z<=n;z++)
        {
            if(!rd[z])
            {
                dfs(z);
                t++;
                for(int i=1;i<=m;i++)
                    for(int j=0;j<=i;j++)
                        for(int k=0;k<=lim[z];k++)
                            f[t][i]=max(f[t][i],f[t-1][j]+dp[z][k][i-j]);
            }
        }
        int ans=-2147483233;
        for(int i=0;i<=m;i++)ans=max(ans,f[t][i]);
        printf("%d
    ",ans);
    }
    View Code

    bzoj1008 堵塞的交通Traffic

    本来以为线段树都是慈眉善目的

    线段树每个节点记一个2*2矩阵中6组连通性

    走的时候左边的节点先走到最左边,右边节点先走到最右边

    然后往中间走

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #define l(x) (x<<1)
    #define r(x) ((x<<1)|1)
    using namespace std;
    const int maxn=800010;
    char opt[15];
    int x1,y1,x2,y2,c;
    struct Segtree
    {
        struct Martix
        {
            int a1[2][2];
            int a2[2];
        };
         
        struct Treenode
        {
            int l,r;
            Martix s;
        }tr[maxn];
        int bl[maxn][2];
         
        Martix upd(Martix s1,Martix s2,int b[])
        {
            Martix res;
            for(int i=0;i<=1;i++) 
                for(int j=0;j<=1;j++) 
                    res.a1[i][j]=s1.a1[i][0] && b[0] && s2.a1[0][j] || s1.a1[i][1] && b[1] && s2.a1[1][j];         
            res.a2[0]=s1.a2[0] || s1.a1[0][0] && b[0] && s2.a2[0] && b[1] && s1.a1[1][1];
            res.a2[1]=s2.a2[1] || s2.a1[0][0] && b[0] && s1.a2[1] && b[1] && s2.a1[1][1];
            return res;
        }
         
        Martix getc(int id,int l,int r)
        {
            int mid=(tr[id].l+tr[id].r)>>1;
            if(l<=tr[id].l && r>=tr[id].r) return tr[id].s;
            else if(l>mid)return getc(r(id),l,r);
            else if(r<=mid)return getc(l(id),l,r);
            else return upd(getc(l(id),l,r),getc(r(id),l,r),bl[id]);
        }
         
        void update(bool f,int id,int sx,int sy,int gx,int gy)
        {
            int mid=(tr[id].l+tr[id].r)>>1;
            if(sx==gx && sy==mid)
            {
                bl[id][sx]=f;
                tr[id].s=upd(tr[l(id)].s,tr[r(id)].s,bl[id]);
            }
            else if(tr[id].l==tr[id].r)
                tr[id].s.a1[0][1]=tr[id].s.a1[1][0]=tr[id].s.a2[0]=tr[id].s.a2[1]=f;
            else
            {
                if(gy<=mid)update(f,l(id),sx,sy,gx,gy);
                else update(f,r(id),sx,sy,gx,gy);
                tr[id].s=upd(tr[l(id)].s,tr[r(id)].s,bl[id]);
            }
        }
        void build(int id,int l,int r)
        {
            tr[id].l=l;tr[id].r=r;
            if(l==r)
            {
                tr[id].s.a1[0][0]=tr[id].s.a1[1][1]=1;
                return;
            }
            int mid=(l+r)>>1;
            build(l(id),l,mid);
            build(r(id),mid+1,r);
        }
         
        void query(int sx,int sy,int gx,int gy)
        {
            Martix L=getc(1,1,sy),Mid=getc(1,sy,gy),R=getc(1,gy,c);
            int res=0;
            for(int i=0;i<=1;i++)
                for(int j=0;j<=1;j++)
                    if(Mid.a1[i][j]&&(i==sx||L.a2[1])&&(j==gx||R.a2[0])){res=1;break;}
            if(res)printf("Y
    ");
            else printf("N
    ");
        }
    }seg;
    int main()
    {
        scanf("%d",&c);
        seg.build(1,1,c);
        while(1) {
            scanf("%s",opt);    
            if(opt[0]=='E') break;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);    
            --x1; --x2;
            if(y1>y2) {
                swap(x1,x2);
                swap(y1,y2);    
            }
            if(opt[0]=='O') seg.update(1,1,x1,y1,x2,y2);
            else if(opt[0]=='C') seg.update(0,1,x1,y1,x2,y2);
            else seg.query(x1,y1,x2,y2);
        }    
        return 0;  
    }
    View Code

    bzoj1019 汉诺塔

    一个经典的汉诺塔型递推

    结合汉诺塔&&BLAH,可想到递推方程: f[x][i] ,g[x][i] 分别表示,当前x柱上有i个圆盘,将它们移至任意另一个柱的操作数,和另一柱子的编号.(如上,这显然对任意连续的i个圆盘,都是唯一固定的)

    f[x][i],g[x][i] 可由 f[][i-1],g[][i-1] 推得:

    汉诺塔的经典转移,先做子问题把x柱上的i-1个圆盘移走,再把第i个大圆盘移走..

    若设y=g[x][i-1],z=1+2+3-y-x(即除x,y以外的柱子编号)

    即1) x上i-1个圆盘移至y上

       2)由于不能对一个圆盘进行重复操作,所以必是将x上的第i个圆盘,移至z

       由于i个圆盘还没叠到一起,所以接下来显然还要再次移动y上的i-1个,这时需要分类讨论:

      若 f[y][i-1]=z:

         3)移到z后,便结束了

         综合以上,这种情况下,f[x][i]=f[x][i-1]+1+f[y][i-1],g[x][i]=z

     若f[y][i-1]=x:

        3)i-1个圆盘移至x

        4)不能对一个圆盘进行重复操作,所以必将z上的第i个圆盘,移至y

        5)因g[x][i-1]=y,所以x上i-1个圆盘移至y,结束

        综合以上,这种情况下,f[x][i]=f[x][i-1]+1+f[y][i-1]+1+f[x][i-1],g[x][i]=y

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define LL long long
    using namespace std;
    int v[5],n,g[5][50];  
    LL f[5][50];  
    int main()  
    {  
            scanf("%d",&n);  
        for (int i=1;i<=6;i++)  
        {  
            char s[5];  
            scanf("%s",s);  
            int from=s[0]-'A'+1,to=s[1]-'A'+1;  
            if (v[from]) continue;  
            v[from]=1;  
            g[from][1]=to,f[from][1]=1;  
        }  
        for (int i=2;i<=n;i++)  
            for (int j=1;j<=3;j++)  
            {  
                int y=g[j][i-1];  
                int z=6-y-j;  
                f[j][i]=f[j][i-1]+1;  
                if (z==g[y][i-1])  
                {  
                    f[j][i]+=f[y][i-1];  
                    g[j][i]=z;  
                }  
                else 
                {  
                    f[j][i]+=f[y][i-1]+1+f[j][i-1];  
                    g[j][i]=y;  
                }  
            }  
        cout<<f[1][n]<<endl;  
        return 0;  
    }  
    View Code

    bzoj1020 安全的航线

    看着莫队的论文战战兢兢的做完这道题

    计算几何入门题

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const double eps=1e-16;
    const int MAXQ=1000000;
    int n,m;double ans; 
    int dcmp(double a)
    {
        if(fabs(a)<eps)return 0;
        else return a>0?1:-1;
    }
    struct Vector
    {
        double x,y;
        Vector operator +(const Vector &a)const{return (Vector){x+a.x,y+a.y};}
        Vector operator -(const Vector &a)const{return (Vector){x-a.x,y-a.y};}
        bool operator ==(const Vector &a)const{return dcmp(x-a.x)==0 && dcmp(y-a.y)==0;}
        Vector operator *(const double &a)const{return (Vector){x*a,y*a};}
        Vector operator /(const double &a)const{return (Vector){x/a,y/a};}
        void Read(){scanf("%lf %lf",&x,&y);}
    }temp[80];
    double dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
    double Length(Vector a){return sqrt(dot(a,a));}
    double Angle(Vector a,Vector b){return acos(dot(a,b)/Length(a)/Length(b));}
    double Xmult(Vector a,Vector b){return a.x*b.y-b.x*a.y;}
    double Area(Vector a,Vector b,Vector c){return Xmult(b-a,c-a);}
    int Intersec(Vector a,Vector b,Vector c,Vector d)
    {
        if(max(a.x,b.x)<min(c.x,d.x))return false;
        if(max(a.y,b.y)<min(c.y,d.y))return false;    
        if(max(c.x,d.x)<min(a.x,b.x))return false;
        if(max(c.y,d.y)<min(a.y,b.y))return false;
        if(Area(c,b,a)*Area(b,d,a)<0)return false;
        if(Area(a,d,c)*Area(d,b,c)<0)return false;
        return true;
    }
    Vector Interpoint(Vector a,Vector b,Vector c,Vector d)
    {
        Vector u=a-c;
        double t=Xmult(d,u)/Xmult(b,d);
        return a+b*t;
    }
    Vector Normal(Vector a){return (Vector){-a.y,a.x};}
    double Distoline(Vector p,Vector a,Vector b)
    {
        Vector v1=b-a,v2=p-a;
        return fabs(Xmult(v1,v2)/Length(v1));
    }
    int Onseg(Vector p,Vector a,Vector b){return dcmp(Xmult(a-p,b-p))==0 && dcmp(dot(a-p,b-p))<0;}
    #define point Vector
    struct Seg{point a,b;}que[1000010];
    struct polygon
    {
        point ps[50];
        int cnt;
        inline int inpo(point &a)
        {
            int tot=0;
            for(int i=1;i<=cnt;i++)
                if(Onseg(a,ps[i],ps[i%cnt+1]))return 1;
            point ray=(point){-10001,a.y+0.1};
            a.y+=0.1;
            for(int i=1;i<=cnt;i++)
                tot+=Intersec(ray,a,ps[i],ps[i%cnt+1]);
            a.y-=0.1;
            return tot&1;
             
        }
    }island[50];
    struct near
    {
        point p;
        double dis;
    };
    near disps(point a,point b,point c)
    {
        if(b==c)return (near){b,Length(b-a)}; 
        Vector v1=c-b,v2=a-b,v3=a-c; 
        if(dcmp(dot(v1,v2))<=0)  return (near){b,Length(v2)}; 
        if(dcmp(dot(v1,v3))>=0)  return (near){c,Length(v3)}; 
        Vector v=Normal(b-c); 
        point ans=Interpoint(a,v,b,v1); 
        return (near){ans,Length(a-ans)};
    }
    bool check(point a)
    {
        for(int i=1;i<=n;i++) 
            if(island[i].inpo(a)) 
                return true; 
        return false;
    }
    near Find(point &p) 
    { 
        if(check(p))  return (near){p,0}; 
        near ans1; 
        ans1.dis=1<<30; 
        for(int i=1;i<=n;i++) 
            for(int j=1;j<=island[i].cnt;j++) 
            { 
                near get=disps(p,island[i].ps[j],island[i].ps[j%island[i].cnt+1]); 
                if(dcmp(ans1.dis-get.dis)>=0)  ans1=get; 
            } 
        ans=max(ans,ans1.dis); 
        return ans1; 
    }
    void dfs()
    { 
        int front=0,rear=0; 
        for(int i=1;i<m;i++) 
            que[++rear]=(Seg){temp[i],temp[i+1]},Find(temp[i]); 
        Find(temp[m]); 
        Seg head; 
        while(front!=rear) 
        { 
            head=que[front=front%MAXQ+1]; 
            point p1=Find(head.a).p,p2=Find(head.b).p,l=head.a,r=head.b,mid=(l+r)/2; 
            while(Length(r-l)>1e-4) 
            { 
                point mid=(r+l)/2; 
                if(Length(mid-p1)<Length(mid-p2))  l=mid; 
                else r=mid; 
            } 
            double nowans=max(Length(l-p1),Length(l-p2)); 
            Find(l); 
            if(ans+0.005<nowans)  que[rear=rear%MAXQ+1]=(Seg){head.a,mid},que[rear=rear%MAXQ+1]=(Seg){mid,head.b}; 
        } 
    } 
    int main()
    {
        scanf("%d %d",&n,&m); 
        for(int i=1;i<=m;i++)
            temp[i].Read(); 
        for(int i=1;i<=n;i++) 
        { 
            scanf("%d",&island[i].cnt); 
            for(int j=1;j<=island[i].cnt;j++) 
                island[i].ps[j].Read(); 
        }
        dfs();
        printf("%.2lf",ans);
    }
    
    View Code

    bzoj1021 循环的债务

    dp[i][j][k]表示第i种钱,第一个人还有j块钱,第二个人还有k块钱时的交换钞票数

    然后依然是个背包

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    using namespace std;
    int x1,x2,x3;
    int cnt[10][10],sum[10];
    const int m[]={0,100,50,20,10,5,1};
    int f[10][1200][1200];
    int g[20];
    int tmp[5];
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
     
    int main()
    {
        scanf("%d%d%d",&x1,&x2,&x3);
        for(int i=0;i<=2;i++)
            for(int j=1;j<=6;j++)
            {
                scanf("%d",&cnt[i][j]);
                sum[i]=sum[i]+cnt[i][j]*m[j];
            }
        int r1=sum[0]-x1+x3,r2=sum[1]-x2+x1;
        g[1]=100;
        for(int i=2;i<=6;i++)g[i]=gcd(g[i-1],m[i]);
        memset(f,0x3f,sizeof(f));
        f[6][sum[0]][sum[1]]=0;
        for(int i=6;i>=1;i--)
        {
            int j=sum[1]+sum[2]+sum[0];
            while((j-r1)%g[i])j--;
            for(;j>=0;j-=g[i])
            {
                int k=sum[1]+sum[2]+sum[0]-j;
                while((k-r2)%g[i])k--;
                for(;k>=0;k-=g[i])
                {
                    if(f[i][j][k]>2000)continue;
                    f[i-1][j][k]=min(f[i-1][j][k],f[i][j][k]);
                    for(int x=0;x<=2;x++)
                    {
                        int y=(x+1)%3,z=(x+2)%3;
                        for(int xx=0;xx<=cnt[x][i];xx++)
                            for(int yy=0;yy<=xx;yy++)
                            {
                                tmp[x]=-xx*m[i];tmp[y]=yy*m[i];z[tmp]=(xx-yy)*i[m];
                                f[i-1][j+tmp[0]][k+tmp[1]]=min(f[i-1][j+tmp[0]][k+tmp[1]],f[i][j][k]+xx);
                            }
                             
                        //Invisible w
                        for(int xx=0;xx<=cnt[y][i];xx++)
                            for(int yy=0;yy<=cnt[z][i];yy++)
                            {
                                tmp[x]=(xx+yy)*m[i];
                                tmp[y]=-xx*m[i];tmp[z]=-yy*m[i];
                                f[i-1][j+tmp[0]][k+tmp[1]]=min(f[i-1][j+tmp[0]][k+tmp[1]],f[i][j][k]+xx+yy);
                            }
                    }
                }
            }
        }
        int ans=f[0][r1][r2];
        printf(ans>=2000?"impossible":"%d",ans);
        return 0;
    }
    View Code

    bzoj1022 小约翰的游戏

    一看这不是Nim吗然后交了个Nim上去

    发现竟然跟Nim是相反的

    然后出现了一个新的小细节:如果有偶数堆,每堆一个石子,先手会赢

    博弈论的题竟然不是Alice和Bob,好评

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int x,sum,flag;
    int T,n;
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            sum=0,flag=0;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&x);
                sum^=x;
                if(x!=1)flag=1;
            }
            if((sum==0 && flag==0) || (sum!=0 && flag==1))printf("John
    ");
            else printf("Brother
    ");
        }
        return 0;
    }
    View Code

    bzoj1023 仙人掌图

    很大意义上来说这不算仙人掌的题

    搞成一棵树找直径

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int first[500100],to[1000100],next[1000100],fa[500100],cnt;
    int ind,dfn[500100],low[500100],depth[500100],q[1000100];
    int a[500100];
    int ans;
    int f[500100];
    int n,m;
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-f;
        for(;isdigit(ch);ch=getchar())x=10*x+ch-'0';
        return x*f;
    }
    inline void add(int u,int v)
    {
        to[++cnt]=v;
        next[cnt]=first[u];
        first[u]=cnt;
    }
    inline void dp(int x,int y)
    {
        int cnt=depth[y]-depth[x]+1,head=1,tail=1,i;  
        for (i=y; i!=x; i=fa[i]) a[cnt--]=f[i]; a[1]=f[x];  
        cnt=depth[y]-depth[x]+1; q[1]=1;  
        for (i=1; i<=cnt; i++) a[i+cnt]=a[i];  
        for (i=2; i<=cnt+(cnt>>1); i++){  
            if (i-q[head]>(cnt>>1)) head++;  
            ans=max(ans,a[i]+i+a[q[head]]-q[head]);  
            while (head<=tail && a[i]-i>=a[q[tail]]-q[tail]) tail--; q[++tail]=i;  
        }  
        for (i=2; i<=cnt; i++) f[x]=max(f[x],a[i]+min(i-1,cnt-i+1));
    }
    inline void Tarjan_dfs(int x)
    {
        dfn[x]=low[x]=++ind;
        for(int i=first[x];i;i=next[i])
        {
            if(to[i]==fa[x])continue;
            if(!dfn[to[i]])
            {
                fa[to[i]]=x;
                depth[to[i]]=depth[x]+1;
                Tarjan_dfs(to[i]);
            }
            low[x]=min(low[x],low[to[i]]);
            if(low[to[i]]>dfn[x])
            {
                ans=max(ans,f[to[i]]+f[x]+1);
                f[x]=max(f[x],f[to[i]]+1);
            }
        }
        for(int i=first[x];i;i=next[i])
            if(fa[to[i]]!=x && dfn[x]<dfn[to[i]])dp(x,to[i]);
    }
    int main()
    {
        n=read(); m=read(); int i;  
        for (i=1; i<=m; i++)
        {
            int tmp=read(),last=0;  
            while (tmp--){  
                int x=read(); if (last){ add(x,last); add(last,x); } last=x;  
            }  
        }  
        Tarjan_dfs(1); 
        printf("%d
    ",ans); 
        return 0;
    }
    View Code

    bzoj1024 生日快乐

    爆搜,每次把蛋糕砍成两块

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    double s;
    double dfs(double x,double y,int n)
    {
        if(n==1)
        {
            return max(x/y,y/x);
        }
        double ans=1e10;
        for(int i=1;i<=n/2;i++)
        {
            double tx=x*i/n,ty=y*i/n;
            ans=min(ans,max(dfs(tx,y,i),dfs(x-tx,y,n-i)));  
            ans=min(ans,max(dfs(x,ty,i),dfs(x,y-ty,n-i)));  
        }
        return ans;
    }
    int x,y,n;
    int main()
    {
        scanf("%d%d%d",&x,&y,&n);
        s=(x*y)/n;
        printf("%lf",dfs(x,y,n));
        return 0;
    View Code

    bzoj1025

    简单推一下就会发现跟博弈论鸡毛关系都没有

    题目变成了

    “求和为n的数列的最小公倍数种数”

    然后随便D一下

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #define ll long long 
    using namespace std;
    int n;
    int check[1010],pri[1010],cnt;
    ll dp[1010][1010],res;
    void laji()
    {
        for(int i=2;i<=1000;i++)
        {
            if(!check[i])pri[++cnt]=i;
            for(int j=1;j<=cnt;j++)
            {
                if(i*pri[j]>1000)break;
                check[i*pri[j]]=1;
                if(i%pri[j]==0)break;
            }
        }
    }
    int main()
    {
        scanf("%d",&n);
        laji();
        dp[0][0]=1;
        for(int i=1;i<=cnt;i++)
        {
            for(int j=0;j<=n;j++)dp[i][j]=dp[i-1][j];
            for(int j=pri[i];j<=n;j*=pri[i])
                for(int k=0;k<=n-j;k++)dp[i][k+j]+=dp[i-1][k];
        }
        for(int i=0;i<=n;i++)res+=dp[cnt][i];
        cout<<res;
    }
    View Code
  • 相关阅读:
    非常棒的Java REST服务器栈
    新闻发布项目——Servlet类(doDelCategoryServlet )
    新闻发布项目——Servlet类(doDelCategoryServlet )
    新闻发布项目——Servlet类(doCategoryModifyServlet )
    新闻发布项目——Servlet类(doCategoryModifyServlet )
    新闻发布项目——Servlet类(doCategoryModifyServlet )
    新闻发布项目——Servlet类(doCategoryaddServlet)
    新闻发布项目——Servlet类(doCategoryaddServlet)
    新闻发布项目——Servlet类(doCategoryaddServlet)
    新闻发布项目——Servlet类(doNews_readServlet )
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/7931473.html
Copyright © 2020-2023  润新知