zoukankan      html  css  js  c++  java
  • 【SDOI2008】解题汇总

    好叭我真的是闲的了...
    

    /—————————————————————————————————————————————/
    BZOJ-2037 【SDOI2008】Sue的小球
    DP+相关费用提前计算
    这里写图片描述
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50769304
    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    struct data{int x,y,v;}can[1010];
    int n;int loc;
    int f[1010][1010][2];
    int w[1010];
    int x[1010];
    
    int cmp(data x,data y){return x.x<y.x;}
    void DP()
    {
        sort(can+1,can+n+1,cmp);
        for (int i=1; i<=n; i++) w[i]=w[i-1]+can[i].v;
        for (int i=1; i<=n; i++)
            f[i][i][0]=f[i][i][1]=can[i].y-abs(can[i].x-loc)*w[n];
        for (int j=2; j<=n; j++)
            for (int i=1; i<=n; i++)
                {
                    int k=i+j-1;
                    if (k>n) break;
                    f[i][k][0]=max(f[i+1][k][0]+can[i].y-abs(can[i].x-can[i+1].x)*(w[i]+w[n]-w[k]),
                                   f[i+1][k][1]+can[i].y-abs(can[i].x-can[k].x)*(w[i]+w[n]-w[k]));
                    f[i][k][1]=max(f[i][k-1][0]+can[k].y-abs(can[k].x-can[i].x)*(w[i-1]+w[n]-w[k-1]),
                                   f[i][k-1][1]+can[k].y-abs(can[k].x-can[k-1].x)*(w[i-1]+w[n]-w[k-1]));
                }
    }
    
    int main()
    {
        n=read();loc=read();
        for (int i=1; i<=n; i++) can[i].x=read();
        for (int i=1; i<=n; i++) can[i].y=read();
        for (int i=1; i<=n; i++) can[i].v=read();
        DP();
        printf("%.3f
    ",(double)max(f[1][n][0],f[1][n][1])/1000);
        return 0;
    }

    /—————————————————————————————————————————————/
    BZOJ-2049 【SDOI2008】Cave 洞穴勘测
    动态树LCT入门,Link、cut操作和判断是否联通
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50839107
    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    #define N 10010
    
    int f[N],son[N][2],val[N],sum[N],tmp[N];bool rev[N];
    bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
    void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}
    void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}
    void up(int x)
    {
        sum[x]=val[x];
            if(son[x][0])sum[x]+=sum[son[x][0]];
            if(son[x][1])sum[x]+=sum[son[x][1]];
    }
    void rotate(int x)
    {
        int y=f[x],w=son[y][1]==x;
        son[y][w]=son[x][w^1];
        if(son[x][w^1])f[son[x][w^1]]=y;
        if(f[y])
            {
                int z=f[y];
                if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
            }
        f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
    }
    
    void splay(int x)
    {
        int s=1,i=x,y;tmp[1]=i;
        while(!isroot(i))tmp[++s]=i=f[i];
        while(s)pb(tmp[s--]);
        while(!isroot(x))
            {
                y=f[x];
                if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
                rotate(x);
            }
        up(x);
    }
    
    void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
    int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
    void makeroot(int x){access(x);splay(x);rev1(x);}
    void link(int x,int y){makeroot(x);f[x]=y;access(x);}
    void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}
    void cut(int x,int y){makeroot(x);cutf(y);}
    int ask(int x,int y){makeroot(x);access(y);splay(y);return sum[y];}
    int find(int x)
    {
        access(x);splay(x);
        int y=x;
        while(son[y][0])y=son[y][0];
        return y;
    }
    int main()
    {
        int n;int m;
        scanf("%d%d
    ",&n,&m);
        for (int i=1; i<=m; i++)
            {
                char com[10];
                scanf("%s",com);
                int a,b;
                scanf("%d%d",&a,&b);
                if (com[0]=='C') link(a,b);
                if (com[0]=='D') cut(a,b);
                if (com[0]=='Q') 
                    if(find(a)==find(b)) puts("Yes");
                                    else puts("No");
            }
        return 0;
    }

    /—————————————————————————————————————————————/
    BZOJ-2186 【SDOI2008】沙拉公主的困惑
    数论 线性筛+逆元
    这里写图片描述
    模p意义下逆元线性推法:(inv[1]=1;) inv[i]=(p-p/i)*inv[p%i]%p;
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50699910
    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int n,m,t,p;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define maxn 10000010
    int prime[1000001];
    bool flag[maxn]={0};
    long long inv[maxn]; 
    long long jc[maxn];
    long long ans[maxn];
    
    
    int quick_pow(long long a,int b,int p)
    {
        int ans=1;
        for(int i=b;i;i>>=1,a=(a*a)%p)
            if(i&1)ans=(ans*a)%p;
        return ans;
    }
    
    void get()
    {
        memset(flag,0,sizeof(flag));
        flag[1]=1; inv[1]=1;jc[1]=1;
        int cnt=0;
        for (int i=2; i<=maxn; i++)
            {
                jc[i]=jc[i-1]*i%p;
                if (i<p) inv[i]=(long long)(p-p/i)*inv[p%i]%p;
                if (!flag[i])
                    prime[++cnt]=i;
                for (int j=1; j<=cnt && i*prime[j]<=maxn; j++)
                    {
                        flag[i*prime[j]]=1;
                        if (i%prime[j]==0) break;
                    }
            }
        ans[1]=1;
        for (int i=2; i<=maxn; i++)
            if (!flag[i])
                ans[i]=ans[i-1]*(i-1)%p*inv[i%p]%p;
            else
                ans[i]=ans[i-1];                        
    }
    
    int main()
    {
        t=read(),p=read();
        get();
        while (t--)
            {
                n=read(),m=read();
                printf("%d
    ",ans[m]*jc[n]%p);
            }   
        return 0;
    }

    /—————————————————————————————————————————————/
    BZOJ-2190 【SDOI2008】仪仗队
    数论 线性筛+欧拉函数
    1.除了坐标带0的点,其他的点都满足gcd(x,y)=1,所以累加欧拉函数φ。。然后加上坐标带0的点即可(2个,一成不变)。。
    2.然后发现具有对称性。。于是只需要搞上方的三角即可。但是对角线那个点重复了一次所以-1
    于是 ans=Σ(φ【1..n-1】)*2+1(+1其实是+2-1)
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50663868
    code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define maxn 40010
    long long prime[maxn],phi[maxn];
    bool flag[maxn]={0};
    int n;
    long long ans;
    
    void get_phi()
    {
        memset(flag,0,sizeof(flag));
        flag[1]=1; 
        int cnt=0;
        for (int i=2; i<=maxn; i++)
            {
                if (!flag[i])
                    prime[cnt++]=i,phi[i]=i-1;
                for (int j=0; j<cnt && i*prime[j]<maxn; j++)
                    {
                        flag[i*prime[j]]=1;
                        if (i%prime[j]==0)
                            {
                                phi[i*prime[j]]=phi[i]*prime[j];
                                break;
                            }
                        else
                            phi[i*prime[j]]=phi[i]*(prime[j]-1);
                    }
            }
    }
    
    int main()
    {
        scanf("%d",&n);
        get_phi();
        ans=2; 
        for (int i=2; i<n; i++)
            ans+=phi[i];
        printf("%lld",ans*2-1);
        return 0;
    }

    /—————————————————————————————————————————————/
    BZOJ-3225 【SDOI2008】立方体覆盖
    线段树+二维扫描线
    于是我先枚举离散后的高,再次基础上控制满足条件的x,y。
    利用扫描线的思想,把每一条竖边取出并按x从左到右快排,然后扫描。如果一条边是始边,把线段树中的y1–y2加1,否则把y1–y2减1。然后对于每一个不同的x,把线段树中覆盖层数大于1的个数*(x[i+1]-x[i])。
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50784825
    code:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define maxn 1010
    const int ff=1200;
    
    struct tre{int sum,del,l,r;}tree[210*2*16];
    int x1[110],x2[110],y1[110],y2[110],z1[110],z2[110]; 
    int tz,tZ,ty,tY;;
    int Z[220],Y[220],z[220],y[220];
    int n,t,tmp;
    int ans=0;
    struct data{int x,l,r,f;}xd[220];
    int pp[2500];int to;
    int L,R,F;int h,W;
    
    void build(int now,int l,int r)
    {
        tree[now].l=l,tree[now].r=r;
        tree[now].sum=tree[now].del=0;
        if (l==r || l+1==r) return;
        int mid=(l+r)>>1;
        build(now<<1,l,mid);
        build(now<<1|1,mid,r); 
    }
    
    void insert(int now)
    {
        if (L<=tree[now].l && R>=tree[now].r) 
            {
                if (!F) tree[now].del++,tree[now].sum=y[tree[now].r]-y[tree[now].l]; else 
                if (!(--tree[now].del)) tree[now].sum=(tree[now].l+1>=tree[now].r)?0:tree[now<<1].sum+tree[now<<1|1].sum;
                return;
            }
        int mid=(tree[now].l+tree[now].r)>>1;
        if (L<mid) insert(now<<1);
        if (R>mid)  insert(now<<1|1);
        if (!tree[now].del) tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;
    }
    
    bool cmp(data a,data b)
    {
        if (a.x!=b.x) return a.x<b.x; 
        return !a.f&&b.f;
    }
    
    int main()
    {
        n=read();
        for (int i=1; i<=n; i++)
            {
                int xx=read(),yy=read(),zz=read(),r=read();
                x1[i]=xx-r;x2[i]=xx+r;
                y1[i]=yy-r;y2[i]=yy+r;
                z1[i]=zz-r;z2[i]=zz+r;      
            }
    
        for (int i=1; i<=n; i++)
            Z[++tZ]=z1[i],Z[++tZ]=z2[i];
        sort(Z+1,Z+tZ+1);Z[0]=Z[1]-1;
        for (int i=1; i<=tZ; i++) if (Z[i]!=Z[i-1]) z[++tz]=Z[i];
    
        for (int i=1; i<tz; i++)
            {
                h=z[i+1]-z[i];
                t=ty=tY=0;
                to=tmp=0;
                for (int j=1; j<=n; j++)
                    if (z1[j]<=z[i] && z[i+1]<=z2[j])
                        {
                            xd[++t].x=x1[j],xd[t].l=y1[j],xd[t].r=y2[j],xd[t].f=0;
                            xd[++t].x=x2[j],xd[t].l=y1[j],xd[t].r=y2[j],xd[t].f=1;
                            Y[++tY]=y1[j],Y[++tY]=y2[j];
                        }   
                sort(Y+1,Y+tY+1);Y[0]=Y[1]-1;
                for (int j=1; j<=tY; j++) if (Y[j]!=Y[j-1]) y[++ty]=Y[j],pp[Y[j]+ff]=++to;
                if (!ty) continue;
                sort(xd+1,xd+t+1,cmp); build(1,1,ty);
    
                for (int j=1; j<t; j++)
                    {
                        W=xd[j+1].x-xd[j].x;
                        L=pp[xd[j].l+ff],R=pp[xd[j].r+ff],F=xd[j].f;
                        insert(1);
                        if (xd[j+1].x!=xd[j].x || j+1==t) tmp+=tree[1].sum*W;
                    }
                ans+=h*tmp;
            }
        printf("%d
    ",ans);
        return 0;
    }

    /—————————————————————————————————————————————/
    BZOJ-3226 【SDOI2008】校门外的区间
    线段树+乱搞
    可以认为是染色问题
    U 区间涂1
    I 两侧区间涂0
    D 区间涂0
    C 两侧涂0,中间取反
    S 区间取反
    然后线段树乱搞就行…
    然后至于开闭区间问题,可以类似的把每个点拆成两个,加以判断即可,即[1,3]=[1,3],[1,3)=[1,2.5]当然程序中不是这么拆的,只是拆乘整数
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50761461
    code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define maxn (65535*2+10)
    int read()
    {
        int x=0,f=0; char ch=getchar();
        while(ch<'0' || ch>'9') { if (ch=='(') f=-1; ch=getchar();}
        while(ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        if(ch==')') f=1;
        return x*2-f;
    }
    
    int tree[maxn<<2],del[maxn<<2]={-1},rev[maxn<<2]={0};
    
    void pushdown(int now,int l,int r)
    {
        if (l==r)
            {
                if (del[now]!=-1)
                    tree[now]=del[now];
                tree[now]=tree[now]^rev[now];
                rev[now]=0;del[now]=-1;
                return;
            }
        if (del[now]!=-1)
            {
                del[now<<1]=del[now<<1|1]=del[now];
                rev[now<<1|1]=rev[now<<1]=0;
            }
        rev[now<<1]=rev[now<<1]^rev[now];
        rev[now<<1|1]=rev[now<<1|1]^rev[now];
        rev[now]=0;del[now]=-1;
    }
    
    void change(int L,int R,int now,int l,int r,int opt)
    {
        if (R<L) return;
        pushdown(now,l,r);
        if(L<=l && R>=r)
            {
                if (opt==-1) {rev[now]=rev[now]^1;}
                        else {del[now]=opt;}
                return;
            }
        int mid=(l+r)>>1;
    
        if (L<=mid)
            change(L,R,now<<1,l,mid,opt);
        if (R>mid)
            change(L,R,now<<1|1,mid+1,r,opt);
    }
    
    int get(int now,int l,int r,int loc)
    {
        pushdown(now,l,r);
        if (l==r)
            return tree[now];
        int mid=(l+r)>>1;
        if (loc<=mid) return get(now<<1,l,mid,loc);
                 else return get(now<<1|1,mid+1,r,loc);
    }
    
    void work()
    {
        char opt[10];int l,r;
        while (scanf("%s",opt)!=EOF)
            {
                l=read(),r=read();
                l+=2;r+=2;  
                switch (opt[0])
                    {
                        case 'U' : change(l,r,1,1,maxn,1);break;
                        case 'I' : change(1,l-1,1,1,maxn,0);change(r+1,maxn,1,1,maxn,0);break;
                        case 'D' : change(l,r,1,1,maxn,0);break;
                        case 'C' : change(1,l-1,1,1,maxn,0);change(r+1,maxn,1,1,maxn,0);change(l,r,1,1,maxn,-1);break;
                        case 'S' : change(l,r,1,1,maxn,-1);break;
                    }
            }
    }
    
    void prin()
    {
        int l=-1,r=-1,f=0;
        for(int i=1;i<=maxn;i++)
            if(get(1,1,maxn,i))
                {
                    if (l==-1) l=i;
                    r=i;
                }
            else 
                {
                    if(l!=-1)
                        {
                            if (f) printf(" ");
                            else f=1;
                            if (l&1) printf("(");
                                else printf("[");
                            printf("%d",l/2-1);
                            printf(",");
                            printf("%d",(r+1)/2-1);
                            if (r&1) printf(")");
                                else printf("]");
                        }
                    l=-1,r=-1;
                }
        if(!f)  puts("empty set");
    }
    
    int main()
    {
        //freopen("BZOJ3226.in","r",stdin);
        work();
        prin();
        return 0;
    }

    /—————————————————————————————————————————————/
    BZOJ-3227 【SDOI2008】红黑树(tree)
    树形DP
    f[i][j][0]=min/max(f[i][j][0],f[k][j-1][1]+f[i-k-1][j-1][1]+1);
    f[i][j][1]=min/max(f[i][j][1],min/max(f[k][j-1][1]+f[i-k-1][j-1][1],min/max(f[k][j][0]+f[i-k-1][j][0],f[k][j][0]+f[i-k-1][j-1][1])));
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50784661
    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    #define maxn 6020
    int n;
    int f[maxn][32][2];
    int maxans,minans;
    
    int main()
    {
        n=read();
        maxans=-0x7fffffff;minans=0x7fffffff;
        memset(f,0x3f,sizeof f);
        f[1][1][0]=1;f[1][1][1]=0;f[2][1][1]=1;
        for (int i=1; i<=n; i++)
            for (int j=1; j<=i; j++)
                if (1<<j > n<<2) break; else
                    for (int k=0; k<=i-2; k++)
                        {
                            f[i][j][0]=min(f[i][j][0],f[k][j-1][1]+f[i-k-1][j-1][1]+1);
                            f[i][j][1]=min(f[i][j][1],min(f[k][j-1][1]+f[i-k-1][j-1][1],
                                       min(f[k][j][0]+f[i-k-1][j][0],f[k][j][0]+f[i-k-1][j-1][1])));
                        }
        for (int i=0; i<=30; i++)
            minans=min(min(minans,f[n][i][0]),f[n][i][1]);
        printf("%d
    ",minans);
        memset(f,-0x3f,sizeof f);
        f[1][1][0]=1;f[1][1][1]=0;f[2][1][1]=1;
        for (int i=1; i<=n; i++)
            for (int j=1; j<=i; j++)
                if (1<<j > n<<2) break; else
                    for (int k=0; k<=i-2; k++)
                        {
                            f[i][j][0]=max(f[i][j][0],f[k][j-1][1]+f[i-k-1][j-1][1]+1);
                            f[i][j][1]=max(f[i][j][1],max(f[k][j-1][1]+f[i-k-1][j-1][1],
                                       max(f[k][j][0]+f[i-k-1][j][0],f[k][j][0]+f[i-k-1][j-1][1])));
                        }
        for (int i=0; i<=30; i++)
            maxans=max(max(maxans,f[n][i][0]),f[n][i][1]);
        printf("%d
    ",maxans);
        return 0;
    }

    /—————————————————————————————————————————————/
    BZOJ-3228 【SDOI2008】棋盘控制
    线段树+一维扫描线+鬼畜处理
    暴力构图,可以每个点实际控制一个菱形,于是可以先把它控制的置成大矩形然后减去四个角;
    线段树扫描线即可,注意边界坑爹
    搞了好几天,坑死人,连个题解都没用TAT
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50822596
    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include <cstdlib>
    using namespace std;
    #define maxk 300005
    long long read()
    {
        long long x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f; 
    }
    
    long long max(long long a,int b)
    {
        if (a>b) return a;
        return b;
    }
    struct data{long long x,y,r;}in[maxk];
    struct dat{
        long long x,y1,y2,k;
        bool operator < (const dat & A) const
            {
                return x<A.x;
            }
    };
    struct da{
        long long st,ed;
        long long sqr()
            {
                if ((ed-st+1)&1) return (ed-st+2)*((ed-st+1)/2+1)/2;
                else return (ed-st+1+2)*((ed-st+1-2)/2+1)/2;
            }
        bool operator < (const da A) const
            {
                return st<A.st;
            }
    };
    int n,m,k;
    #define maxn 1200005
    struct SegmentTree{
        int del[maxn],tree[maxn];
        int Y[maxk];
        void clear()
            {
                memset(del,0,sizeof(del));
                memset(tree,0,sizeof(tree));
            }
        void updata(int now,long long l,long long r)
            {
                if (del[now]>0) tree[now]=r-l;
                else tree[now]=tree[now<<1]+tree[now<<1|1];
            }
        void insert(int now,int l,int r,int L,int R,int num)
            {
                int mid=(l+r)>>1;
                if (L<=Y[l] && R>=Y[r]) del[now]+=num; else
                    {
                        if (L<Y[mid]) insert(now<<1,l,mid,L,R,num);
                        if (R>Y[mid]) insert(now<<1|1,mid,r,L,R,num);
                    }
                updata(now,Y[l],Y[r]);
            }
        long long query()
            {
                return tree[1];
            }
    }T;
    
    struct cal{
        dat line[maxk];
        int tot,n;
        long long x1[maxk],x2[maxk],y1[maxk],y2[maxk];
        long long calc()
            {
                T.clear();
                for (int i=1; i<=n; i++) T.Y[i*2-1]=y1[i],T.Y[i*2]=y2[i];
                sort(T.Y+1,T.Y+2*n+1); tot=1;
                for (int i=2; i<=2*n; i++) if (T.Y[i]!=T.Y[i-1]) T.Y[++tot]=T.Y[i];
                for (int i=1; i<=n; i++)
                    {
                        line[i*2-1].x=x1[i]; line[i*2-1].y1=y1[i]; line[i*2-1].y2=y2[i];
                        line[i*2].x=x2[i]; line[i*2].y1=y1[i]; line[i*2].y2=y2[i];
                        line[i*2-1].k=1; line[i*2].k=-1;
                    }
                sort(line+1,line+2*n+1);
                long long ans=0,last=0;
                for (int i=1; i<=2*n; i++)
                    {
                        if (i!=1) ans=ans+last*(long long)((long long)(line[i].x)-(long long)line[i - 1].x);
                        if (last<0) {int a;a+=1;}
                        if (line[i].y1!=line[i].y2) T.insert(1,1,tot,line[i].y1,line[i].y2,line[i].k);
                        last=T.query();
                    }
            return ans;
        }
    }calc1, calc2;
    struct calcc{
        int n;
        da tri[maxk],tmp;
        long long cal()
            {
                if (n==0) return 0ll;
                long long ans=0; da tmp;
                sort(tri+1,tri+n+1);
                ans=tri[1].sqr(); int now=1;
                for (int i=2; i<=n; i++)
                    {
                        if (tri[i].st>=tri[now].st && tri[i].ed<=tri[now].ed) continue;
                        if (tri[i].st>tri[now].ed)
                            {
                                ans+=tri[i].sqr(); now=i; continue;
                            }
                        ans+=tri[i].sqr();tmp.st=tri[i].st; tmp.ed=tri[now].ed;
                        ans-=tmp.sqr(); now=i;
                    }
                return ans;
            }
    }tc[5];
    
    int main()
    {
        n=read(),m=read(),k=read();
        for (int i=1; i<=k; i++) in[i].x=read(),in[i].y=read(),in[i].r=read();
        calc1.n=calc2.n=k;
        for (int i=1; i<=k; i++)
            {
                int tmp=in[i].r-((in[i].x+in[i].y+in[i].r)&1);
                calc1.x1[i]=(in[i].x+in[i].y-tmp)>>1;
                calc1.y1[i]=(in[i].y-tmp-in[i].x)>>1;
                calc1.x2[i]=((in[i].x+in[i].y+ tmp)>>1)+1;
                calc1.y2[i]=((in[i].y+tmp-in[i].x)>>1)+1;
            }
        for (int i=1; i<=k; i++)
            {
                int tmp=in[i].r-(!((in[i].x+in[i].y+in[i].r)&1));
                calc2.x1[i]=(in[i].x+in[i].y-tmp-1)>>1;
                calc2.y1[i]=(in[i].y-tmp-in[i].x-1)>>1;
                calc2.x2[i]=((in[i].x+in[i].y+tmp-1)>>1)+1;
                calc2.y2[i]=((in[i].y+tmp-in[i].x-1)>>1)+1;
            }
        long long ans=0;
        ans=calc1.calc()+calc2.calc();
        for (int i=1; i<=k; i++) if (in[i].r>=in[i].x)
            {
                ++tc[1].n; 
                tc[1].tri[tc[1].n].st=in[i].y-(in[i].r-in[i].x);
                tc[1].tri[tc[1].n].ed=in[i].y+(in[i].r-in[i].x);
            }
        for (int i=1; i<=k; i++) if (in[i].r>=in[i].y)
            {
                ++tc[2].n; 
                tc[2].tri[tc[2].n].st=in[i].x-(in[i].r-in[i].y);
                tc[2].tri[tc[2].n].ed=in[i].x+(in[i].r-in[i].y);
            }
        for (int i=1; i<=k; i++) if (in[i].r>=n+1-in[i].x)
            {
                ++tc[3].n; 
                tc[3].tri[tc[3].n].st=in[i].y-(in[i].r-(n+1-in[i].x));
                tc[3].tri[tc[3].n].ed=in[i].y+(in[i].r-(n+1-in[i].x));
            }
        for (int i=1; i<=k; i++) if (in[i].r>=m+1-in[i].y)
            {
                ++tc[4].n; 
                tc[4].tri[tc[4].n].st=in[i].x-(in[i].r-(m+1-in[i].y));
                tc[4].tri[tc[4].n].ed=in[i].x+(in[i].r-(m+1-in[i].y));
            }
        for (int i=1; i<=4; i++)
            ans-=tc[i].cal();
        long long m1=0,m2=0,m3=0,m4=0;
        for (int i=1; i<=k; i++)
            {
                if (in[i].r>=in[i].x+in[i].y) m1=max(m1,1+in[i].r-in[i].x-in[i].y);
                if (in[i].r>=in[i].x+(m+1-in[i].y)) m2=max(m2, 1+in[i].r-in[i].x-(m+1-in[i].y));
                if (in[i].r>=in[i].y+(n+1-in[i].x)) m3=max(m3, 1+in[i].r-in[i].y-(n+1-in[i].x));
                if (in[i].r>=(m+1-in[i].y)+(n+1-in[i].x)) m4=max(m4,1+in[i].r-((m+1-in[i].y)+(n+1-in[i].x)));
            }
        ans+=m1*(m1+1)/2+m2*(m2+1)/2+m3*(m3+1)/2+m4*(m4+1)/2;
        printf("%lld
    ",ans);
        return 0;
    }

    /—————————————————————————————————————————————/
    BZOJ-3229 【SDOI2008】石子合并
    黑科技 GarsiaWachs算法
    石子合并问题的专门算法GarsiaWachs算法:
    先从序列中找第一个st【k】使得st【k-1】<=st【k+1】然后合并st【k-1】与st【k】;
    再从序列中从k往前找第一个st【j】使得st【j】>st【k-1】+st【k】然后将这个合并后的放在j位置后;
    如此往复直到只剩一堆;
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50784554
    code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    int st[50000];
    int n,t;
    int ans=0;
    
    void work(int k)
    {
        int tmp=st[k]+st[k-1];
        ans+=tmp;
        for (int i=k; i<t-1; i++)
            st[i]=st[i+1];
        t--;
        int j=0;
        for (j=k-1; j>0 && st[j-1]<tmp; j--)
            st[j]=st[j-1];
        st[j]=tmp;
        while (j>=2 && st[j]>=st[j-2])
            {
                int d=t-j;
                work(j-1);
                j=t-d;
            }
    }
    
    int main()
    {
        n=read();
        for (int i=0; i<n; i++) st[i]=read();
        t=1;ans=0;
        for (int i=1; i<n; i++)
            {
                st[t++]=st[i];
                while (t>=3 && st[t-3]<=st[t-1])
                    work(t-2);
            }
        while (t>1) work(t-1);
        printf("%d
    ",ans);
        return 0;
    }

    /—————————————————————————————————————————————/
    BZOJ-3231 【SDOI2008】递归数列
    矩阵连乘+快速幂
    这里写图片描述
    不稳定の传送门:http://blog.csdn.net/dad3zz/article/details/50756641
    code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    long long read()
    {
        long long x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    long long k,m,n,p;
    long long s=0;
    long long cc[50],bb[50];
    struct Mat{
        long long da[50][50];
        Mat(){memset(da,0,sizeof(da));}   
    };
    
    Mat mul(Mat A,Mat B)
    {
        Mat C;
        for (int i=1; i<=k+1; i++)
            for (int j=1; j<=k+1; j++)
                for (int kk=1; kk<=k+1; kk++)
                    C.da[i][j]=(C.da[i][j]+(A.da[i][kk]*B.da[kk][j])%p)%p;
        return C;
    } 
    
    Mat quick_pow(Mat A,long long x)
    {
        Mat re;
        for (int i=1; i<=k+1; i++) re.da[i][i]=1;
        for (long long i=x; i; i>>=1,A=mul(A,A))
            if (i&1) re=mul(re,A);
        return re;
    }
    
    Mat a;
    Mat b;
    void init()
    {
        for (int i=1;i<=k;i++)  a.da[i][1]=a.da[i][k+1]=cc[i];
        for (int i=2;i<=k;i++)  a.da[i-1][i]=1;
        a.da[k+1][k+1]=1;
        for (int i=1;i<=k;i++)  b.da[1][i]=bb[k-i+1];
        b.da[1][k+1]=s;
    }
    
    long long work(long long x)
    {
        if (x==0) return b.da[1][k+1];
        Mat re;
        re=quick_pow(a,x);
        re=mul(b,re);
        return re.da[1][k+1];
    }
    
    int main()
    {
        k=read();
        for (int i=1; i<=k; i++) bb[i]=read();
        for (int i=1; i<=k; i++) cc[i]=read();   
        m=read(),n=read(),p=read();
        for (int i=1; i<=k; i++) bb[i]%=p,s=(s+bb[i])%p,cc[i]%=p;
        long long ans=0;
        if (n<=k) 
            {
                for (int i=m; i<=n; i++) ans=(ans+bb[i])%p;
                printf("%lld
    ",ans);
                return 0;
            }
        init();
        ans=work(n-k);
        if (m>k) ans=(ans-work(m-k-1))%p;
            else for (int i=1; i<m; i++) ans=(ans-bb[i])%p;
        ans=(ans+p)%p;
        printf("%lld
    ",ans);
        return 0;
    }

    /—————————————————————————————————————————————/
    一发成果图:(O(∩_∩)O~~开心)
    这里写图片描述

  • 相关阅读:
    两种无限递归菜单
    python导出项目所有依赖库,在新环境中安装所有依赖库
    python3.6中安装Crypto模块
    在Django中settings文件内,配置MySQL和Redis
    Django继承AbstractUser新建User Model时出现fields.E304错误
    django_orm操作MySQL数据库,批量插入数据
    在用脚手架搭建vue项目时,运行vue报错
    django命令行运行失败
    redis pipline 操作
    tcpdump 与 MySQL sniffer 【转】
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346172.html
Copyright © 2011-2022 走看看