2013年6月11日 13:12

BZOJ1407: [Noi2002]Savage【扩展欧几里得】

BZOJ

观察到n的范围极小,m的范围也才1000000。那就可以枚举答案了。

枚举答案M。满足对于任何(i,j),都满足C[i]+x*P[i]=C[j]+x*P[j](mod M)的最小正整数解x大于min(L[i],L[j]),或者不存在x。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;ll An=0,c[20],p[20],l[20]; int n;
ll ext_gcd(ll a,ll b,ll&x,ll&y){
    if(!b){ x=1; y=0; return a;}
    ll xx,yy,d=ext_gcd(b,a%b,xx,yy);
    x=yy; y=xx-a/b*yy; return d;
}ll equ(ll a,ll b,ll c){
    ll x,y,d=ext_gcd(a,c,x,y); if(b%d) return -1;
    x*=b/d; while(x>c/d)x-=c/d;
    while(x<0) x+=c/d; return x;
}int check(ll m){
    for(int i=1;i<n;i++) for(int j=i+1;j<=n;j++){
        ll d; if(p[i]>=p[j])d=equ(p[i]-p[j],c[j]-c[i],m);
        else d=equ(p[j]-p[i],c[i]-c[j],m);
        if(d!=-1&&d<=min(l[i],l[j]))return 1;
    }return 0;
}int main(){
    scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld%lld%lld",&c[i],&p[i],&l[i]),An=max(An,c[i]);
    for(;check(An);An++); printf("%lld\n",An); return 0;
}

Comments(0)

Tags:

2013年6月10日 21:13

BZOJ2661: [BeiJing wc2012]连连看【费用流】

BZOJ

二分图。赤果果的费用流。其实是KM。但是不会写。只好写费用流替代了。

先O(n^2)判哪些数对(x,y)可行。然后连边,做最大费用流。

因为每个数只能取一次。那么我把(x,y)和(y,x)都连了一遍。那么结果除以二。

判断选了几对,只要看T点的流量有多少不是从TT流过来的就行了。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxm=5000000,inf=1061109567;
int h[10005],p[maxm],c[maxm],cost[maxm],n1[maxm],q[maxm],sp[10005],inq[10005];
int sq[1000005]={0},S,T,TT,An=0,path[maxm],pre[10005],tot=0;
inline void ae(int a,int b,int cc,int co){
    p[tot]=b; c[tot]=cc; cost[tot]=co;  n1[tot]=h[a]; h[a]=tot++;
    p[tot]=a; c[tot]=0;  cost[tot]=-co; n1[tot]=h[b]; h[b]=tot++;
}inline int spfa(){
    memset(sp,63,sizeof(sp));   memset(inq,0,sizeof(inq));
    int head=0,tail=1; sp[S]=0; q[0]=S; inq[S]=1; pre[S]=-1;
    while(head!=tail){
        int u=q[head++]; if(head>=maxm) head-=maxm; inq[u]=0;
        for(int i=h[u];~i;i=n1[i])
            if(c[i]>0&&sp[p[i]]>sp[u]+cost[i]){
                path[p[i]]=i, pre[p[i]]=u, sp[p[i]]=sp[u]+cost[i];
                if(!inq[p[i]]){ inq[p[i]]=1, q[tail++]=p[i]; if(tail>=maxm) tail-=maxm;}
            }
    }return sp[T]!=inf;
}inline int aug(){
    int delta=inf,  flow=0;
    for(int i=T;pre[i]!=-1;i=pre[i]) delta=min(delta,c[path[i]]);
    for(int i=T;pre[i]!=-1;i=pre[i]){
        c[path[i]]-=delta, c[path[i]^1]+=delta;
        flow+=cost[path[i]]*delta;
    }return flow;
}inline int cf(){
    int ret=0; while(spfa()) ret+=aug(); return ret;
}int gcd(int a,int b){
    return (!b)?a:gcd(b,a%b);
}int main(){
    int a,b;    scanf("%d%d",&a,&b);    memset(h,-1,sizeof(h));
    for(int i=1;i<=1000;i++) sq[i*i]=i; S=0;TT=(b-a+1)<<1|1;T=TT+1;
    for(int i=a;i<=b;i++) for(int j=i+1;j<=b;j++)
        if(sq[j*j-i*i]&&gcd(sq[j*j-i*i],i)==1){
            ae(j-a+1,b-a+1+i-a+1,1,-i-j);
            ae(i-a+1,b-a+1+j-a+1,1,-i-j);
        }ae(TT,T,inf,0);
    for(int i=1;i<=b-a+1;i++) ae(S,i,1,0), ae(i,TT,1,0), ae(b-a+1+i,T,1,0);
    int An1,An2=-cf();
    for(int i=h[T];~i;i=n1[i]) if(p[i]==TT)An=b-a+1-c[i];
    printf("%d %d\n",An>>1,An2>>1);  return 0;    
}

Comments(0)

Tags:

2013年6月10日 17:34

BZOJ2252: [2010Beijing wc]矩阵距离【bfs】

BZOJ

正在纠结这类水题有没有写题解的必要?

暴露智商了。囧。我智商-∞岂会轻易告诉你们?

把所有1的点放进队列。bfs。没了。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mp make_pair 
#define qsize 2000000
typedef pair<int,int> pii; pii q[qsize];
int head=0,tail=0,n,m,d[1005][1005];    char s[1005];
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int main(){
    scanf("%d%d",&n,&m);    memset(d,63,sizeof(d));
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++) if(s[j]-'0') q[tail++]=mp(i,j), d[i][j]=0;
    }while(head!=tail){
        pii u=q[head++]; if(head>=qsize) head-=qsize;
        for(int k=0;k<4;k++){
            int xx=u.first+dx[k],yy=u.second+dy[k];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&d[u.first][u.second]+1<d[xx][yy]){
                d[xx][yy]=d[u.first][u.second]+1;
                q[tail++]=mp(xx,yy); if(tail>=qsize) tail-=qsize;
            }
        }
    }for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++) printf("%d ",d[i][j]);
        printf("\n");
    }return 0;
}

Comments(0)

Tags:

2013年6月10日 13:02

BZOJ2251: [2010Beijing Wc]外星联络【后缀数组】

BZOJ

题意:给一个字符串。输出在原串中出现次数大于1的子串的出现次数。这些本质不同的子串按字典序大小排序输出次数。

一眼题?嗯。、后缀数组就行了、根据sa数组和height数组扫一遍。前后扫height数组。

反正n≤3000,没必要二分了。还要写rmq啥的多麻烦啊是吧、、然后就行了、感觉跑的蛮快的?

第一次加了fread和fwrite还变慢了、、

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=2000005;
int tmp1[maxn],tmp2[maxn],cs[maxn],cv[maxn],rank[maxn],height[maxn],sa[maxn];
char s[maxn],str[maxn];
inline bool cmp(int *r,int a,int b,int l){
    return  r[a]==r[b] && r[a+l]==r[b+l];
}inline void da(char *r,int *sa,int n,int m){
    int i,j,p,*x=tmp1,*y=tmp2,*t;
    for(i=0;i<m;i++)cs[i]=0;
    for(i=0;i<n;i++)cs[x[i]=r[i]]++;
    for(i=1;i<m;i++)cs[i]+=cs[i-1];
    for(i=n-1;i>=0;i--)sa[--cs[x[i]]]=i;
    for(j=1,p=1;p<n;j<<=1,m=p){
        for(p=0,i=n-j;i<n;i++)y[p++]=i;
        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        for(i=0;i<n;i++)cv[i]=x[y[i]];
        for(i=0;i<m;i++)cs[i]=0;
        for(i=0;i<n;i++)cs[cv[i]]++;
        for(i=1;i<m;i++)cs[i]+=cs[i-1];
        for(i=n-1;i>=0;i--)sa[--cs[cv[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
}inline void ch(char *r,int n){
    int i,j,k=0;
    for(i=0;i<n;i++)rank[sa[i]]=i;
    for(i=0;i<n;height[rank[i++]]=k)
        for(k=max(k-1,0),j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}int main(){
    int n;  scanf("%d%s",&n,str);
    for(int i=0;i<n;i++)str[i]++;   str[n++]=0;
    da(str,sa,n,256);   ch(str,n);
    for(int i=1;i<n;i++){
        for(int j=height[i]+1;sa[i]+j<n;j++){
            int l,r;
            for(l=i;l>=0 && height[l]>=j;l--);
            for(r=i+1;r<=n && height[r]>=j;r++);
            if(r-l<=1)continue;
            printf("%d\n",r-l);
        }
    }return 0;
}

Comments(0)

Tags:

2013年6月09日 18:06

BZOJ1196: [HNOI2006]公路修建问题【二分判定】

BZOJ

煞笔的煞笔又来发水题题解了!

二分答案。先判一级公路然后判二级公路。没了。

1A什么的不必多说。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct E{ int u,v,c1,c2;}e[20005];
inline bool C(E a,E b){ return a.c1<b.c1;}
int F[10005],n,k,m; char buf[2000000],*pt=buf;
int GF(int x){  return x==F[x]?x:F[x]=GF(F[x]);}
inline int getint(){ 
    int r=0;while(*pt<'0'||*pt>'9')pt++;while(*pt>='0'&&*pt<='9')r=r*10+*pt++-48;return r;
}inline int ok(int lmt){
    int ck=0,ca=0;
    for(int i=1;i<=n;i++) F[i]=i;
    for(int i=1;i<=m;i++){
        if(e[i].c1<=lmt){
            int u=GF(e[i].u),v=GF(e[i].v);
            if(u!=v) F[u]=v,ck++,ca++;
            if(ca==n-1) return 1;
        }else{
            if(ck<k) return 0;
            if(min(e[i].c1,e[i].c2)>lmt) continue;
            int u=GF(e[i].u),v=GF(e[i].v);
            if(u!=v) F[u]=v,ca++;
            if(ca==n-1) return 1;
        }
    }return 0;
}int main(){
    fread(pt,1,2000000,stdin);  int i;
    for(n=getint(),k=getint(),m=getint(),i=1;i<m;i++)
        e[i].u=getint(),e[i].v=getint(),e[i].c1=getint(),e[i].c2=getint();
    sort(e+1,e+m+1,C);  int l=0,r=1000000009,mid;
    while(l<=r){
        mid=l+r>>1;
        if(ok(mid)) r=mid-1;    else    l=mid+1;
    }printf("%d\n",l);return 0;
}

Comments(0)

Tags:

2013年6月09日 15:38

BZOJ1692: [Usaco2007 Dec]队列变换【后缀数组】

BZOJ

题意:给你一个字符串。每次取出第一个字符或最后一个字符,放到新的字符串(初始为空)后面。求最小字典序的新字符串。

比如样例:ACDBCB。按这样的顺序拿:头尾尾尾头尾。这样得到ABCBCD。可以证明没有比它字典序更小的了。

一开始我先YY了个很傻比的贪心。第一个字符和最后一个字符比较。取小的。然后O(n)扫一遍。(画外音:你煞笔啊、gold的题目就给你这么水掉啊!、、)本着这种态度很快就发现样例都过不了。先取出A、B。然后是取队头的C还是队尾的C呢。这时就发现光比较这一个字符的大小是不够的。要比较整个字符串和整个字符串反转过来的字符串的字典序大小,才能决定取哪个。

那么想到了什么呢?很明显就是后缀数组。

把这个字符串反转一遍接在原字符串后面,中间加一个分隔符(最好是小于'A'的,比如'@')。然后求出rank数组。

下标  0  1 2 3  4 5 6  7 8  9 10 11 12

字符  A C D B C B @ B C B D  C   A

那么维护两个指针,一个从0开始,一个从n+1(反转的字符串的起点)开始。比较rank的大小,每次取小的先输出。OK!

(fread、fwrite蛮好的、轻松rank3)



#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=100000;
int tmp1[maxn],tmp2[maxn],cs[maxn],cv[maxn],rank[maxn],sa[maxn],str[maxn];
char s[maxn],buf[maxn],*p=buf,buf2[maxn],*o=buf2;
inline bool cmp(int *r,int a,int b,int l){
    return  r[a]==r[b] && r[a+l]==r[b+l];
}inline void da(char *r,int *sa,int n,int m){
    int i,j,p,*x=tmp1,*y=tmp2,*t;
    for(i=0;i<m;i++)cs[i]=0;
    for(i=0;i<n;i++)cs[x[i]=r[i]]++;
    for(i=1;i<m;i++)cs[i]+=cs[i-1];
    for(i=n-1;i>=0;i--)sa[--cs[x[i]]]=i;
    for(j=1,p=1;p<n;j<<=1,m=p){
        for(p=0,i=n-j;i<n;i++)y[p++]=i;
        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        for(i=0;i<n;i++)cv[i]=x[y[i]];
        for(i=0;i<m;i++)cs[i]=0;
        for(i=0;i<n;i++)cs[cv[i]]++;
        for(i=1;i<m;i++)cs[i]+=cs[i-1];
        for(i=n-1;i>=0;i--)sa[--cs[cv[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }for(i=0;i<n;i++)rank[sa[i]]=i;
}int main(){
    fread(p,1,maxn,stdin);  int t=0,n=0;
    while(*p<'0'||*p>'9')p++;
    while(*p>='0'&&*p<='9')n=n*10+*p++-48;
    for(int i=1;i<=n;i++){ 
        while(*p<'A'||*p>'Z')p++;
        s[t++]=*p++; 
    }s[t++]='A'-1;
    for(int i=n-1;~i;i--)   s[t++]=s[i];    s[t++]='\0';
    da(s,sa,t,256);
    int j=0,k=n+1,c=0;
    for(int i=1;i<=n;i++)str[c++]=rank[j]>rank[k]?k++:j++;
    for(int i=0;i<n;i++){
        if(i&&i%80==0)*o++='\n';
        *o++=s[str[i]];
    }fwrite(buf2,1,o-buf2,stdout);
    return 0;
}

Comments(0)

Tags:

2013年6月09日 10:21

BZOJ2752: [HAOI2012]高速公路(road)【线段树】

BZOJ

题意:修改区间内的数、询问区间内任意子段和的期望值。

然后我们尝试把每次的答案求出来。然后对这个式子乱搞。发现对于每个数a[i],维护a[i],i*a[i],i*i*a[i]就好了、

那么线段树维护就行了。好了没了。(其实是我懒得写题解了、、、

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define lson l,mid,ls
#define rson mid+1,r,rs
#define root 1,n,1
typedef long long ll;
const int maxn=500005;
ll a[maxn]={0},b[maxn]={0},c[maxn]={0},add[maxn]={0};
char buf[5000000],*pt=buf,buf2[5000000],*o=buf2;
inline ll getint(){
    ll r=0,f=1; while((*pt!='-')&&(*pt<'0'||*pt>'9'))pt++; if(*pt=='-')f=-1, pt++;
    while(*pt>='0'&&*pt<='9')r=r*10+*pt++-48;   return r*f;
}inline char getop(){
    while(*pt!='C'&&*pt!='Q')pt++;  return *pt;
}inline void print(ll x){
    char str[30],*p=str; if(!x)*o++=48;
    else{ while(x) *p++=x%10+48,x/=10; while(p--!=str)*o++=*p;}
}inline void pushup(ll rt){
    a[rt]=a[ls]+a[rs], b[rt]=b[ls]+b[rs], c[rt]=c[ls]+c[rs];
}inline void pushdown(ll l,ll r,ll rt){
    ll lc=mid-l+1, rc=r-mid, rr=mid, ll=mid+1;  
    if(add[rt]){
        add[ls]+=add[rt];
        a[ls]+=lc*add[rt];
        b[ls]+=(l+rr)*lc*add[rt]>>1;
        c[ls]+=(rr*(rr+1)*(rr<<1|1)-(l-1)*l*(l-1<<1|1))/6*add[rt];
        add[rs]+=add[rt];
        a[rs]+=rc*add[rt];
        b[rs]+=(ll+r)*rc*add[rt]>>1;
        c[rs]+=(r*(r+1)*(r<<1|1)-(ll-1)*ll*(ll-1<<1|1))/6*add[rt];
        add[rt]=0;
    }
}void update(ll L,ll R,ll d,ll l,ll r,ll rt){
    if(L<=l&&r<=R){
        add[rt]+=d;
        a[rt]+=(r-l+1)*d;
        b[rt]+=(l+r)*(r-l+1)*d>>1;
        c[rt]+=(r*(r+1)*(r<<1|1)-(l-1)*l*(l-1<<1|1))/6*d;
        return;
    }pushdown(l,r,rt);
    if(L<=mid)  update(L,R,d,lson);
    if(mid<R)   update(L,R,d,rson);
    pushup(rt);
}void query(ll L,ll R,ll&A,ll&B,ll&C,ll l,ll r,ll rt){
    if(L<=l && r<=R){
        A=a[rt],B=b[rt],C=c[rt]; return;
    }pushdown(l,r,rt);
    ll SA=0,SB=0,SC=0,TA,TB,TC;
    if(L<=mid)  query(L,R,TA,TB,TC,lson), SA+=TA, SB+=TB, SC+=TC;
    if(mid<R)   query(L,R,TA,TB,TC,rson), SA+=TA, SB+=TB, SC+=TC;
    A=SA,B=SB,C=SC;
}inline ll gcd(ll a,ll b){
    return (!b)?a:gcd(b,a%b);
}int main(){ 
    fread(pt,1,5000000,stdin);  ll n,q,u,v,w,TA,TB,TC,A,B,C;
    for(n=getint(),q=getint();q;q--){
        if(getop()=='C'){
            u=getint(),v=getint(),w=getint();
            update(u,v-1,w,root);
        }else{
            u=getint(),v=getint();
            query(u,v-1,TA,TB,TC,root);
            A=(u+v-1)*TB+TA*(v-v*u)-TC;
            B=(v-u+1)*(v-u)>>1;
            C=gcd(A,B);
            print(A/C);*o++='/';print(B/C);*o++='\n';
        }
    }fwrite(buf2,1,o-buf2,stdout);return 0;
}

Comments(0)

Tags:

2013年6月08日 21:31

BZOJ2748: [HAOI2012]音量调节【背包】

BZOJ

原来省选题也有裸背包啊、、

if (F[i-1][j]) then F[i][j+c[i]]=F[i][j-c[i]]=1

好了水掉了

#include<cstdio>
int f[52][1005]={0},n,st,ed,c[52];
int main(){
    scanf("%d%d%d",&n,&st,&ed); for(int i=1;i<=n;i++)scanf("%d",&c[i]);
    f[0][st]=1;  for(int i=1;i<=n;i++)   for(int j=0;j<=ed;j++){
        if(!f[i-1][j])  continue;
        if(j+c[i]<=ed)  f[i][j+c[i]]=1;
        if(j-c[i]>=0)   f[i][j-c[i]]=1;
    }int An;    for(An=ed;~An;An--) if(f[n][An]) break; printf("%d\n",An);
}

Comments(0)

Tags:

2013年6月08日 20:22

BZOJ1066: [SCOI2007]蜥蜴【网络流】

BZOJ

自己YY出来了?估计应该是比较简单的网络流入门题吧。。

既然每个点(i,j)最多只能通过c[i][j]个蜥蜴。那么很自然地想到拆点。(i,j)→(i,j)'连上容量为c[i][j]的边。(i,j)为入点。(i,j)'为出点。

对于所有有蜥蜴的点,从S给它连一条容量为1的边。对于所有可以跳到外面的点,连到T,容量是c[i][j]。

然后n^4枚举在内部跳来跳去的情况。最后跑网络流就好了。

连T的边的时候我一直在傻×、、一开始算的是到(0,0)的距离≤d、、果然还是太弱了哎、、

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000,maxm=500000,inf=1000000009;
int p[maxm],c[maxm],n1[maxm],q[maxn],h1[maxn],d[maxn],h[maxn],g[maxn],id[25][25];
int S,T,n,m,k,tot=0,cnt=0,N=0;    char s[25];
inline void ae(int x,int y,int z){
    p[tot]=y;   c[tot]=z;   n1[tot]=h[x];   h[x]=tot++;
    p[tot]=x;   c[tot]=0;   n1[tot]=h[y];   h[y]=tot++;
}inline int bfs(){
    memset(d,0xff,sizeof(d));   int r=d[q[0]=S]=0;
    for(int l=0;l<=r;l++)
        for(int k=h[q[l]];~k;k=n1[k])
            if(c[k] && !~d[p[k]])   d[q[++r]=p[k]]=d[q[l]]+1;
    return ~d[T];
}int dfs(int x=S,int lmt=inf){
    if(x==T)    return lmt; int flow;
    for(int &k=g[x];~k;k=n1[k]){
        if(c[k] && d[p[k]]==d[x]+1 && (flow=dfs(p[k],min(lmt,c[k])))){
            c[k]-=flow; c[k^1]+=flow;   return flow;
        }
    }return 0;
}int main(){
    scanf("%d%d%d",&n,&m,&k);   k;   S=0;    T=801;  memset(h,0xff,sizeof(h));
    for(int i=1,j;i<=n;i++) for(scanf("%s",s+1),j=1;j<=m;j++)   if(s[j]-'0'){
        id[i][j]=++cnt;
        ae((id[i][j]<<1)-1,id[i][j]<<1,s[j]-'0');
        if(min(min(i,n-i+1),min(j,m-j+1))<=k)ae(id[i][j]<<1,T,s[j]-'0');
    }for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int ii=1;ii<=n;ii++) for(int jj=1;jj<=m;jj++){
        if(!id[i][j]||!id[ii][jj])  continue;
        if((ii-i)*(ii-i)+(jj-j)*(jj-j)<=k*k)  ae(id[i][j]<<1,(id[ii][jj]<<1)-1,inf);
    }for(int i=1,j;i<=n;i++) for(scanf("%s",s+1),j=1;j<=m;j++) if(s[j]=='L'){
        N++; if(id[i][j])   ae(S,(id[i][j]<<1)-1,1);
    }int An=0,f=0;   while(bfs()){   memcpy(g,h,sizeof(h));  while(f=dfs())  An+=f;}
    printf("%d\n",N-An);    return 0;
} 

Comments(0)

Tags:

2013年6月08日 16:40

BZOJ3203: [Sdoi2013]保护出题人【单调栈+二分+凸壳】

BZOJ

【吐槽:我不想保护出题人。。。】

首先把读入的a数组变成前缀和。然后就可以发现y数组其实就是这个东西这就是确保杀死j~i(j≤i)这一段僵尸的最小速度。伤害的和是a[i]-a[j-1],第j个~第i个之间的距离是di-dj,还要加上x[i]才是与家的距离。很绕吗?自己脑补吧。。

观察这个式子比较像求直线的斜率。那么我们把它转化为两点之间的斜率好了。把跟i有关的看成一个点,跟j有关的看成一个点。

那么就是(x[i]+d*i,a[i])(d*j,a[j-1])两个点。然后只要求斜率了!!!

那么用单调栈维护一个凸壳就好了!!!计算斜率的时候二分。二分的时候先判是不是在凸壳的外部,然后取栈里面最上面那个就好了。

很好。nlogn了。

这是样例,有线连着的点是转化过的(d*j,a[j-1])。其中虚线是最后形成的凸壳。

查询第i次的时候就是先转化为(x[i]+d*i,a[i])这个点,然后二分凸壳上的点求最大的斜率就好。

比如查询第一次。凸壳(黄线)中只有(2,0)这个点。要查询的是(5,3)。很明显斜率只能是1。

查询第二次。查询的点是(5,4)。凸壳中有两个点(2,0),(4,3)。选前者的算出的斜率1.3333比后者的1要优。

然后以此类推就可以解决全部询问。

这道题在八中上rank1了我会告诉你们?介于是rank1我就不发rank1的代码了、、这个是目前rank10的、、





#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef double D; D a[100005],x[100005],d,An=0;
struct P{D x,y;P(){};P(D _x,D _y):x(_x),y(_y){};}p[100005];
D cross(P a,P b,P c){ return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);}
int st[100005],top=0,n;
int main(){
    scanf("%d%lf",&n,&d);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&a[i],&x[i]);
        a[i]+=(p[i].y=a[i-1]);  p[i].x=i*d;
    }for(int i=1;i<=n;i++){
        while(top&&cross(p[st[top]],p[i],p[st[top-1]])<0)top--;
        st[++top]=i;     P s(x[i]+i*d,a[i]);
        int j=1,l=1,r=top,mid;  while(l<=r){
            mid=l+r>>1;
            if(cross(p[st[mid]],p[st[mid-1]],s)<0)j=max(j,mid),l=mid+1;else r=mid-1;
        }An+=(s.y-p[st[j]].y)/(s.x-p[st[j]].x);
    }printf("%.0lf\n",An);  return 0;
}

Comments(5)

Tags:

Copyright © 2007

Webdesign, tvorba www stránek

Valid XHTML 1.1