【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\n",(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",&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\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",ans);
    return 0;
}

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

posted @ 2016-03-07 23:55  DaD3zZ  阅读(237)  评论(0编辑  收藏  举报