zoukankan      html  css  js  c++  java
  • 十连测泛做 题解2

    life

    这个出题人怎么这么暴力啊

    image

    image

    我们把所有长度为l-1的串搞出来,每个长度为l的串前缀往后缀连边。

    那么我们只要找到一条欧拉回路就行了。

    但是这题tmd卡空间。。。暴力建边过不了,似乎要用哈希值动态建图。。。就当过了好了

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <time.h>
    #include <stdlib.h>
    #include <string>
    #include <bitset>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <algorithm>
    #include <sstream>
    #include <stack>
    #include <iomanip>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    typedef pair<int,int> pii;
    typedef long long ll;
    typedef double ld;
    typedef vector<int> vi;
    #define fi first
    #define se second
    #define fe first
    #define S 1000000
    int M=0,fst[S],vb[S+S],vc[S+S],nxt[S+S];
    void ad_de(int a,int b,int c)
    {
        ++M; nxt[M]=fst[a]; fst[a]=M; vb[M]=b; vc[M]=c;
    }
    int c,l;
    char s[S+S];
    void dfs(int d=0,int ch=0,int tat=0,int lst=0,int lch=0)
    {
        if(d==l)
        {
            ad_de(ch,lst,lch);
            return;
        }
        for(int x=0;x<c;x++)
        {
            dfs(d+1,(d)?(ch*c+x):ch,tat*c+x,tat,x);
        }
    }
    int st[S+S],ss=0;
    void euler(int c)
    {
        for(int i=fst[c];i;)
        {
            fst[c]=nxt[i];
            st[++ss]=vc[i];
            euler(vb[i]);
            i=fst[c];
        }
        fst[c]=0;
    }
    int main()
    {
        freopen("life.in","r",stdin);
        freopen("life.out","w",stdout);
        scanf("%d%d%s",&c,&l,s);
        if(l==1)
        {
            puts(s);
            return 0;
        }
        dfs(0); euler(0);
        printf("%d
    ",ss+l-1);
        for(int i=1;i<l;i++) putchar(s[0]);
        for(int i=ss;i>=1;i--) putchar(s[st[i]]);
    }

    gene

    image

    1<=n,m<=130000,s由ACTG组成。

    首先我们把字符串,例如abcd变成|a|b|c|d|,然后跑manacher,搞出p数组(向左向右最长对称长度,从0开始)。

    经过观察我们可以知道,如果x位置这个字符是分隔符,那么实际以它为中心存在回文串个数为p[k]/2,否则存在(p[k]+1)/2个。

    那我们对于一个询问[l,r],考虑在这个新串里面就是[2l-1,2r+1],(实际写出来好像由于从0开始标号不是这样...详见代码)那么设L=2l-1,R=2r+1。

    我们可以发现:

    image

    r-l+1是为了补偿x不为分隔符时的那个1。

    接下来我们来暴力讨论一波那个min。

    如果k-L<=R-k时,即L<=k<=l+r。

    此时答案就成了min{f[k],k-L},那么如果f[k]<=k-L,即f[k]-k<=-L,就将f[k]计入答案。如果f[k]-k>L,就将k-L计入答案。

    如果k-L>R-k,l+r<k<=R。

    答案成了min{f[k],R-k},如果f[k]<=R-k,即f[k]+k<=R,就将f[k]计入答案,否则将R-k计入答案。

    两棵可持久化线段树(维度为x,f[x]-x和x,f[x]+x)解决问题...

    出题人强行卡常...卡不过去

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <time.h>
    #include <stdlib.h>
    #include <string>
    #include <bitset>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <algorithm>
    #include <sstream>
    #include <stack>
    #include <iomanip>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    typedef pair<int,int> pii;
    typedef long long ll;
    typedef double ld;
    typedef vector<int> vi;
    #define fi first
    #define se second
    #define fe first
    #define SZ 666666
    #define inf 1000000001
    int A;
    struct tup
    {
    ll s[3];
    tup() {s[0]=s[1]=s[2]=0;}
    tup(ll a,ll b,ll c) {s[0]=a; s[1]=b; s[2]=c;}
    ll& operator [] (int a) {return s[a];}
    };
    bool operator < (tup a,tup b) {return 0;}
    tup operator + (tup a,tup b)
    {return tup(a[0]+b[0],a[1]+b[1],a[2]+b[2]);}
    tup operator - (tup a,tup b)
    {return tup(a[0]-b[0],a[1]-b[1],a[2]-b[2]);}
    typedef pair<pii,tup> rec;
    bool cmp(rec a,rec b) {return a.fi.fi<b.fi.fi;}
    struct Query2D
    {
    #define S2 7000000
    int ch[S2][2],rots[SZ],an,pn;
    tup sum[S2]; rec ps[SZ];
    Query2D() {an=pn=0;}
    int P_,S_; tup Q_;
    void ins_(int r1,int& r2,int l,int r)
    {
        r2=++an;
        sum[r2]=sum[r1]+Q_;
        if(l==r) return;
        int mid=l+r>>1;
        if(P_<=mid)
        ins_(ch[r1][0],ch[r2][0],l,mid), ch[r2][1]=ch[r1][1];
        else
        ins_(ch[r1][1],ch[r2][1],mid+1,r), ch[r2][0]=ch[r1][0];
    }
    ll query_(int r1,int r2,int l,int r)
    {
        if(l>P_||sum[r1][S_]==sum[r2][S_]) return 0;
        if(r<=P_) return sum[r2][S_]-sum[r1][S_];
        int mid=l+r>>1;
        ll ans=query_(ch[r1][0],ch[r2][0],l,mid);
        if(P_>mid) ans+=query_(ch[r1][1],ch[r2][1],mid+1,r);
        return ans;
    }
    void ins(int x,int y,tup z)
    {
        ++x; y+=A;
        ++pn; ps[pn].fi.fi=x; ps[pn].fi.se=y; ps[pn].se=z;
        //if(pn&131071);else cerr<<pn<<"mdzz
    ";
    }
    int fst[SZ],nxt[SZ];
    void pre()
    {
        for(int i=1;i<=pn;i++)
        {
            int x=ps[i].fi.fi;
            nxt[i]=fst[x]; fst[x]=i;
        }
        int cur=1,rr=0,rt=0;
        for(int i=1;i<=A+A;i++)
        {
            for(int cur=fst[i];cur;cur=nxt[cur])
            {
                P_=ps[cur].fi.se; Q_=ps[cur].se;
                ins_(rr,rt,0,A+A+A); rr=rt;
            }
            rots[i]=rt;
        }
        //cerr<<an<<"yikesaiting
    ";
    }
    ll query(int x1,int x2,int y1,int y2,int s)
    {
        if(x1>x2||y1>y2) return 0;
        ++x1; ++x2; y1+=A; y2+=A;
        P_=y2; S_=s; ll ans=query_(rots[x1-1],rots[x2],0,A+A+A);
        P_=y1-1; ans-=query_(rots[x1-1],rots[x2],0,A+A+A);
        return ans;
    }
    }k_fk_m_k,k_fk_a_k;
    int n,m,p[SZ];
    char dna[SZ],s[SZ];
    void manacher()
    {
        int ml=0,id=0;
        for(int i=1;s[i];i++)
        {
            if(ml>i) p[i]=min(p[2*id-i],p[id]+id-i);
            else p[i]=1;
            while(i-p[i]>=0&&s[i+p[i]]==s[i-p[i]]) p[i]++;
            if(i+p[i]>ml) ml=i+p[i], id=i;
        }
        for(int i=1;s[i];i++) --p[i];
    }
    #define gc getchar()
    int g_i()
    {
        int tmp=0; bool fu=0; char s;
        while(s=gc,s!='-'&&(s<'0'||s>'9')) ;
        if(s=='-') fu=1; else tmp=s-'0';
        while(s=gc,s>='0'&&s<='9') tmp=tmp*10+s-'0';
        if(fu) return -tmp; else return tmp;
    }
    #define gi g_i()
    #define pob
    #define pc(x) putchar(x)
    namespace ib {char b[100];}
    inline void pint(int x)
    {
        if(x==0) {pc(48); return;}
        if(x<0) {pc('-'); x=-x;}
        char *s=ib::b;
        while(x) *(++s)=x%10, x/=10;
        while(s!=ib::b) pc((*(s--))+48);
    }
    int main()
    {
        freopen("gene.in","r",stdin);
        freopen("gene.out","w",stdout);
        scanf("%d%d%s",&n,&m,dna);
        int ps=0; s[ps++]='*';
        for(int i=0;dna[i];i++)
        {
            s[ps++]=dna[i];
            s[ps++]='*';
        }
        s[ps]=0;
        manacher();
        A=ps+3;
        for(int i=0;s[i];i++)
        {
            k_fk_m_k.ins(i,p[i]-i,tup(p[i],i,1));
            k_fk_a_k.ins(i,p[i]+i,tup(p[i],i,1));
        }
        k_fk_m_k.pre(); k_fk_a_k.pre();
        while(m--)
        {
            int l=gi,r=gi,L=l+l-2,R=r+r; --l; --r;
            ll ans=r-l+1;
            ans+=k_fk_m_k.query(L,l+r,-A,-L,0);
            ans+=k_fk_m_k.query(L,l+r,-L+1,A+A,1)
            -k_fk_m_k.query(L,l+r,-L+1,A+A,2)*L;
            ans+=k_fk_a_k.query(l+r+1,R,-A,R,0);
            ans+=k_fk_a_k.query(l+r+1,R,R+1,A+A,2)*R
            -k_fk_a_k.query(l+r+1,R,R+1,A+A,1);
            ans/=2;
            printf("%I64d
    ",ans);
        }
    }

    jhaha(暴力的题目名称

    image

    n<=20000,m<=100。

    我们考虑一个思博暴力,令f[k][i]为前k个建了i个记者站,最后一个记者站为k的最小花费(包括i之前的没覆盖的费用)。

    image

    方程大概这样...

    我们考虑从小到大枚举i。

    首先我们可以随便sort一下拿个指针弄一下,搞出前i个,第i个造了记者站,没覆盖的费用。后i个同理。

    那么首先我们可以这样求出f[?][1]这一堆。

    然后我们考虑已知f[?][x-1],如何求出f[?][x],我们从小到大枚举第一维s,如果我们考虑从p转移,那么就要从f[p][x-1]+cost(p...s)转移。

    现在s变大的时候我们可以发现和之前指针搞的一样,渐渐地会有一些村庄w不能被s覆盖,那么p如果不能覆盖w,答案就要加上P[w]。

    我们可以二分出哪里结束不能覆盖,然后拿棵线段树维护一下就行了。

    好消息,我又被卡常了...

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <time.h>
    #include <stdlib.h>
    #include <string>
    #include <bitset>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <algorithm>
    #include <sstream>
    #include <stack>
    #include <iomanip>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    typedef pair<int,int> pii;
    typedef long long ll;
    typedef double ld;
    typedef vector<int> vi;
    #define fi first
    #define se second
    #define fe first
    #define SZ 666666
    int bits[SZ]; int n,m;
    int d[SZ],c[SZ],r[SZ],p[SZ];
    int M=32768,M2=M+M,ls[SZ],rs[SZ];
    int qq[SZ],tag[SZ];
    void build()
    {
        for(int i=M+1;i<=M+M;i++) ls[i]=rs[i]=i-M;
        for(int i=M-1;i;i--)
        {
            ls[i]=ls[i+i], rs[i]=rs[i+i+1], qq[i]=min(qq[i+i],qq[i+i+1]);
        }
    }
    void pd(int x)
    {
        if(tag[x])
        {
            qq[x]+=tag[x];
            if(x+x<=M2) tag[x+x]+=tag[x], tag[x+x+1]+=tag[x];
            tag[x]=0;
        }
    }
    void upd(int x)
    {
        pd(x+x); pd(x+x+1);
        qq[x]=min(qq[x+x],qq[x+x+1]);
    }
    void edit(int x,int ql,int qr,int v)
    {
        if(x>M2||ql>qr) return;
        pd(x);
        if(ql==ls[x]&&qr==rs[x]) {tag[x]+=v; return;}
        int mid=ls[x]+rs[x]>>1;
        edit(x+x,ql,min(qr,mid),v);
        edit(x+x+1,max(mid+1,ql),qr,v);
        upd(x);
    }
    int gmin(int x,int ql,int qr)
    {
        if(x>M2||ql>qr) return 1000000000;
        pd(x);
        if(ql==ls[x]&&qr==rs[x]) return qq[x];
        int mid=ls[x]+rs[x]>>1;
        int ans=min(gmin(x+x,ql,min(qr,mid)),gmin(x+x+1,max(mid+1,ql),qr));
        upd(x); return ans;
    }
    int gmin(int x)
    {
        return gmin(1,1,x);
    }
    void edt(int x,int y)
    {
        edit(1,1,x,y);
    }
    void init(int n,int* x)
    {
        memset(qq,127/3,sizeof(qq));
        memset(tag,0,sizeof(tag));
        for(int i=n;i>=1;i--) qq[i+M]=x[i];
        build();
    }
    int lf[SZ],qzc[SZ],hzc[SZ];
    pii t[SZ];
    int f[101][20001];
    #define gc getchar()
    int g_i()
    {
        int tmp=0; bool fu=0; char s;
        while(s=gc,s!='-'&&(s<'0'||s>'9')) ;
        if(s=='-') fu=1; else tmp=s-'0';
        while(s=gc,s>='0'&&s<='9') tmp=tmp*10+s-'0';
        if(fu) return -tmp; else return tmp;
    }
    #define gi g_i()
    int main()
    {
        freopen("jhaha.in","r",stdin);
        freopen("jhaha.out","w",stdout);
        n=gi, m=gi;
        for(int i=2;i<=n;i++) d[i]=gi;
        for(int i=1;i<=n;i++) c[i]=gi;
        for(int i=1;i<=n;i++) r[i]=gi;
        for(int i=1;i<=n;i++) p[i]=gi;
        for(int i=1;i<=n;i++)
        lf[i]=lower_bound(d+1,d+1+n,d[i]-r[i])-d;
        for(int i=1;i<=n;i++) t[i]=pii(d[i]-r[i],i);
        sort(t+1,t+1+n);
        for(int i=n,j=n;i>=1;i--)
        {
            hzc[i]=hzc[i+1];
            while(j>=1&&t[j].first>d[i])
            hzc[i]+=p[t[j--].second];
        }
        for(int i=1;i<=n;i++) t[i]=pii(d[i]+r[i],i);
        sort(t+1,t+1+n);
        for(int i=1,j=1;i<=n;i++)
        {
            qzc[i]=qzc[i-1];
            while(j<=n&&t[j].first<d[i])
            qzc[i]+=p[t[j++].second];
        }
        for(int i=1;i<=n;i++) f[1][i]=qzc[i]+c[i];
        for(int i=2;i<=m;i++)
        {
            init(n,f[i-1]); //要把数组倒过来 
            for(int j=1,k=1;j<=n;j++)
            {
                while(k<=n&&t[k].first<d[j])
                edt(lf[t[k].second]-1,p[t[k].second]), ++k;
                f[i][j]=gmin(j-1)+c[j];
            }
        }
        int ans=2147483647;
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++) ans=min(ans,f[i][j]+hzc[j]);
        }
        printf("%d
    ",ans);
    }

    后面一天居然tm只放了第一题那个鬼畜计算几何dp题的题解。。。就跳过吧

    xor

    有n个数,求所有2^n个子集异或和中二进制下1的个数的k次方之和,模10^9+7。

    image

    1<=n,k<=40,0<=ai<2^40。

    怎么一堆40总感觉有点问题...

    首先我们发现{a,b,...}与{a^b,b,...}答案一样。

    我们考虑将这些数二进制写出来,排成一行一行地,高斯消元。

    接下来我们考虑高斯消元后,如果非零的数不超过S,2^S暴力一波即可。

    然后我们考虑被约过的(恰好只有一个1的)列,这个显然不止S个,设dp[i][j][k]表示前i行,被约过的列选了j列,剩下的异或起来为k的方案数,一波大暴力即可。

    这部分复杂度为40*S*2^(40-S)。

    经过反复尝试我们可以发现S=25的时候跑的最快。

    不过一如既往还是被卡常了。。。要跑1.3s。。。不管了

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <time.h>
    #include <stdlib.h>
    #include <string>
    #include <bitset>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <algorithm>
    #include <sstream>
    #include <stack>
    #include <iomanip>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    typedef pair<int,int> pii;
    typedef long long ll;
    typedef double ld;
    typedef vector<int> vi;
    #define fi first
    #define se second
    #define fe first
    int n,k,nc=0;
    bool one[2333];
    ll a[2333],nz[2333],ans=0;
    ll MOD=1000000007;
    ll qp(ll a,ll b)
    {
        ll ans=1;
        while(b)
        {
            if(b&1) ans=ans*a%MOD;
            a=a*a%MOD; b>>=1;
        }
        return ans;
    }
    ll rps[333],rp[2097153];
    #define S 25
    void force(int c=0,ll s=0)
    {
        if(c>=nc)
        {
            int a=0;
            for(int i=1;i<=3;i++) a+=rp[s%2097152], s/=2097152;
            ans=(ans+rps[a])%MOD;
            return;
        }
        force(c+1,s);
        force(c+1,s^nz[c]);
    }
    int c1[2333];
    ll rms[2333];
    ll dp[41][41][65537];
    ll gans()
    {
        ans=0; nc=n;
        for(int i=0;i<n;i++) nz[i]=a[i];
        force(); ll t=ans;
        nc=0; ans=0; return t;
    }
    int main()
    {
        freopen("xor.in","r",stdin);
        freopen("xor.out","w",stdout);
        scanf("%d%d",&n,&k);
        for(int i=0;i<=2097152;i++)
        {
            int t=i,g=0;
            while(t) g+=t&1, t>>=1;
            rp[i]=g;
        }
        for(int i=0;i<=300;i++) rps[i]=qp(i,k);
        for(int i=0;i<n;i++) scanf("%I64d",a+i);
        ans=0; nc=0;
        int cp=0,cc=0,qt=0;
        for(int j=0;j<40;j++)
        {
            ll c=1LL<<j;
            int cur=cp;
            while(cur<n&&!(a[cur]&c)) ++cur;
            if(cur>=n) continue;
            one[j]=1; ++cc;
            swap(a[cp],a[cur]);
            for(int i=0;i<n;i++)
            {
                if(i!=cp&&(a[i]&c)) a[i]^=a[cp];
            }
            ++cp;
        }
        for(int i=0;i<n;i++) if(a[i]) nz[nc++]=a[i];
        if(nc<=S)
        {
            force();
            ans=(ans*qp(2,n-nc)%MOD+MOD)%MOD;
            cout<<ans<<"
    ";
            return 0;
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<40;j++)
            {
                ll c=1LL<<j;
                if(one[j]) c1[i]+=bool(a[i]&c);
                else rms[i]=rms[i]*2+bool(a[i]&c);
            }
        }
        dp[0][c1[0]][rms[0]]=1;
        dp[0][0][0]=1;
        int ls=1<<(40-cc);
        for(int i=1;i<n;i++)
        {
            memcpy(dp[i],dp[i-1],sizeof(dp[i-1]));
            for(int j=c1[i];j<=cc;j++)
            {
                for(int k=0;k<ls;k++)
                {
                    dp[i][j][k]+=dp[i-1][j-c1[i]][k^rms[i]];
                    if(dp[i][j][k]>=MOD) dp[i][j][k]-=MOD;
                }
            }
        }
        ll ans=0;
        for(int j=0;j<=cc;j++)
        {
            for(int k=0;k<ls;k++)
            {
                int co1=j+rp[k];
                ans+=qp(co1,::k)*dp[n-1][j][k]%MOD;
                ans%=MOD;
            }
        }
        ans=(ans%MOD+MOD)%MOD;
        cout<<ans<<"
    ";
    }

    kmp

    求老司机讲一下弦图染色方案数怎么求啊。。。写到一半写不下去

    rng

    啊这题有必要截个图

    image

    这个题一看就是爬山或者退火嘛。。。

    写了一个爬山80分

    //By zzq
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <algorithm>
    #include <string.h>
    #include <time.h>
    #include <math.h>
    #include <set>
    #include <map>
    using namespace std;
    int m;
    typedef double db;
    char c[2333];
    db qfl[2333],qyl[2333];
    db qf[2333],qy[2333];
    typedef pair<db,int> sta;
    sta chk(int s)
    {
        if(s==0||s==(1<<m)-1) return sta(-233333333,s);
        int c_f=0,c_y=0;
        for(int i=0;i<m;i++)
        {
            if(s&(1<<i)) ++c_y; else ++c_f;
        }
        //(c_f*q_f)/(c_f*q_f+c_y)
        double gl=0;
        int t=0; bool x=0;
        for(int i=0;i<1000;i++)
        {
            bool y=s&(1<<(c[i]-'a'));
            if(!i)
            {
                t=1; x=y; continue;
            }
            if(x==0)
            {
                double gf=(c_f*qf[t])/(c_f*qf[t]+c_y);
                if(!y) gl+=log(gf); else gl+=log(1-gf);
            }
            else
            {
                double gy=(c_y*qy[t])/(c_y*qy[t]+c_f);
                if(y) gl+=log(gy); else gl+=log(1-gy);
            }
            if(x!=y) t=0;
            ++t; x=y;
        }
        return sta(gl,s);
    }
    int main()
    {
        freopen("rng.in","r",stdin);
        freopen("rng.out","w",stdout);
        srand(123456);
        qf[0]=qy[0]=1;
        for(int i=1;i<=1000;i++)
        {
            qfl[i]=qfl[i-1]+log(0.5);
            qyl[i]=qyl[i-1]+log(2/3.0);
            qf[i]=qf[i-1]/2;
            qy[i]=qy[i-1]*2/3;
        }
        scanf("%d",&m);
        for(int p=1;p<=100;p++)
        {
            scanf("%s",c);
            sta ans=chk(0);
            int rp=0;
            for(int i=1;i<=10;i++)
            {
                sta cur;
                //gen cur
                {
                int s=0;
                for(int i=0;i<m;i++) if(rand()&1) s|=1<<i;
                cur=chk(s);
                }
                //mountain!
                int t=0;
                while(clock()<3.5*i*p)
                {
                    ++t;
                    int sp=cur.second^(1<<(rand()%m));
                    sta now=chk(sp);
                    if(now>cur) cur=now, t=0;
                    if(t>=14) break;
                }
                ans=max(ans,cur);
            }
            ans=max(ans,chk(((1<<m)-1)^ans.second));
            int s=ans.second;
            for(int i=0;i<m;i++)
            {
                if(s&(1<<i)) putchar('C');
                else putchar('V');
            }
            puts("");
        }
        cerr<<clock()<<"
    ";
    }

    tourist(题目名称取这个吃枣药丸

    小Y来到了一个新的城市旅行。她发现了这个城市的是个n个点简单多边形。她想在多边形内等概率随机选取两点,问这两个点的期望曼哈顿距离。

    要求绝对精度1e-3,n<=10^5,坐标为[-10^9,10^9]的整数。

    首先在做这题之前我们需要有微积分的基本知识(雾

    例如我们要积一个次数不高的函数...但是感觉如果算系数吃枣药丸

    如果你确定它是不超过三次的...那么有一个辛普森积分公式可以解决这个问题。

    公式:f(x)在[m,n]上的积分为$frac{2f(m)+4f(frac{m+n}{2})+2f(n)}{6}$。

    而对于四次、五次,我们可以使用神奇的高斯积分公式。

    (此处参考https://en.wikipedia.org/wiki/Gaussian_quadrature

    image

    image

    n个点高斯积分公式的可以积2n-1次的函数!(不是n个点积n次)那么用这个表0~9次的函数都可以这样积分。

    用n=3的就足够积五次函数了。

    啊扯远了...首先这题x和y可以分开算。我们就考虑计算x好了。

    比如P(t)表示随机两个点的线段通过x=t这条直线的概率,那么答案就是对P(t)积分对吧。

    那么我们可以发现P(t)=2*左边面积*右边面积/总面积^2(一个在左边,一个在右边,反之亦然)

    那我们把x坐标离散,扫描每一段分别积分,那么这时左边面积、右边面积、都是二次函数,乘在一起是四次函数。

    Q:为什么左边面积右边面积是二次函数?

    A:额因为考虑面积就是平行于y轴的直线在多边形内部的长度的积分,那就是一次函数的积分,二次函数。

    我们考虑怎么算这个一边的面积,那我们就是要计算这个被积的一次函数:

    image

    这个就很简单了...我们定一个方向为正方向,把这些一次函数扫描维护一下,加加减减一下就行了。(什么?与y轴平行的边?忽略即可)

    哦,还要绝对值...这个好办,我们积分的时候把两个端点带进去检验一下...

    那么我们算出了一边的面积,只要一波高斯积分即可!

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    #include <time.h>
    #include <stdlib.h>
    #include <string>
    #include <bitset>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <algorithm>
    #include <sstream>
    #include <stack>
    #include <iomanip>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    typedef pair<int,int> pii;
    typedef long long ll;
    typedef double ld;
    typedef double db;
    typedef vector<int> vi;
    #define fi first
    #define se second
    #define fe first
    #define SZ 666666
    int n,xs[SZ],ys[SZ];
    typedef pair<ld,ld> yc;
    typedef pair<int,yc> rec;
    rec rr[SZ];
    int xx[SZ];
    yc operator + (yc a,yc b) {return yc(a.fi+b.fi,a.se+b.se);}
    yc operator - (yc a) {return yc(-a.fi,-a.se);}
    ld Xs[3]={-sqrt(0.6),0,sqrt(0.6)},Ws[3]={5/9.0,8/9.0,5/9.0};
    int main()
    {
        freopen("tourist.in","r",stdin);
        freopen("tourist.out","w",stdout);
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d%d",xs+i,ys+i);
        ld alls=0;
        for(int i=0;i<n;i++) alls+=xs[i]*(ld)ys[(i+1)%n]-(ld)xs[(i+1)%n]*ys[i];
        alls=fabs(alls)/2;
        ld ans=0;
        for(int _=0;_<=1;_++)
        {
        for(int i=0;i<n;i++) xx[i]=xs[i];
        int s1=0;
        for(int i=0;i<n;i++)
        {
            int x=(i+1)%n;
            if(xs[i]==xs[x]) continue;
            db k=(ys[x]-ys[i])/double(xs[x]-xs[i]);
            db b=ys[i]-xs[i]*k;
            yc cur=yc(k,b);
            rr[++s1]=rec(xs[i],cur);
            rr[++s1]=rec(xs[x],-cur);
        }
        sort(rr+1,rr+1+s1);
        sort(xx,xx+n);
        int xn=unique(xx,xx+n)-xx;
        yc cur; int s=1;
        ld ls=0,rs=alls;
        for(int i=0;i<xn-1;i++)
        {
            int l=xx[i],r=xx[i+1];
            while(s<=s1&&rr[s].fi==l) cur=cur+rr[s++].se;
            yc cy=cur;
            if(cy.fi*l+cy.se<-1e-6) cy=-cy;
            else if(cy.fi*r+cy.se<-1e-6) cy=-cy;
            ld area=(cy.fi*l+cy.se+cy.fi*r+cy.se)*ld(r-l)/2;
            rs-=area;
            ld X,A=cy.fi/2,B=cy.se,lv=A*l*l+B*l,rv=A*r*r+B*r; //强行人工积分
            ld lx=ls-lv,rx=rs+rv,jf=0;
            for(int i=0;i<3;i++)
            {
                X=(r-l)/2.0*Xs[i]+(l+r)/2.0;
                jf+=Ws[i]*(lx+A*X*X+B*X)*(rx-A*X*X-B*X);
            }
            jf=(r-l)*jf/alls/alls;
            ans+=jf; ls+=area;
        }
        for(int i=0;i<n;i++) swap(xs[i],ys[i]);
        }
        printf("%.10lf
    ",ans);
    }

    施工中。。。

  • 相关阅读:
    Spark学习笔记2(spark所需环境配置
    Spark学习笔记1(初始spark
    zookeeper基本讲解及基本命令和配置 (转)
    计算机网络面试常考(转载)
    C++面试笔试题汇总
    复杂指针解析
    如何限制一个类对象只在栈(堆)上分配空间?
    虚函数实现机制
    C++内存分配方式详解
    C++中指针和引用的区别(转载)
  • 原文地址:https://www.cnblogs.com/zzqsblog/p/5826409.html
Copyright © 2011-2022 走看看