【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~~开心)