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\n",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("\n");
    }
};
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\n",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\n", 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\n",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\n",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\n",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\n",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\n");
        else printf("N\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\n");
        else printf("Brother\n");
    }
    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\n",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

 

posted @ 2017-11-30 20:26  探险家Mr.H  阅读(325)  评论(0编辑  收藏  举报