NOI2016部分题解

D1T1优秀的拆分
枚举AABB中AB的交界处,其实就是要计算每个位置AA的数量,算这个东西有个经典套路:
枚举A的长度,每A个字符设置一个关键点,任意一个A一定覆盖且仅覆盖1个关键点,枚举相邻的两个关键点,后缀数组上st表O(1) lcp求他们往左往右匹配长度
O ( n l o g n )

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 61000;
const int maxd = 18;

struct Suffix_Array
{
    int s[maxn],sa[maxn],rank[maxn];
    int fir[maxn],sec[maxn];
    int t[maxn];
    void sort_(int str[],int ans[],int sa[],int n,int m)
    {
        for(int i=0;i<=m;i++) t[i]=0;
        for(int i=1;i<=n;i++) t[str[sa[i]]]++;
        for(int i=1;i<=m;i++) t[i]+=t[i-1];
        for(int i=n;i>=1;i--) ans[t[str[sa[i]]]--]=sa[i];
    }
    void Get_SA(int n,int m)
    {
        for(int i=1;i<=n;i++) rank[i]=i;
        sort_(s,sa,rank,n,m);
        rank[sa[1]]=1;
        for(int i=2;i<=n;i++) rank[sa[i]]=rank[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]);
        int t=1;
        while(rank[sa[n]]!=n)
        {
            for(int i=1;i<=n;i++)
            {
                fir[i]=rank[i];
                sec[i]=i+t>n?0:rank[i+t];
                sa[i]=i;
            }
            sort_(sec,rank,sa,n,n);
            sort_(fir,sa,rank,n,n);
            rank[sa[1]]=1;
            for(int i=2;i<=n;i++) rank[sa[i]]=rank[sa[i-1]]+
                                (fir[sa[i]]!=fir[sa[i-1]]||sec[sa[i]]!=sec[sa[i-1]]);
            t<<=1;
        }
    }
    int height[maxn];
    void Get_Height(int n)
    {
        height[1]=0; int k=0;
        for(int i=1;i<=n;i++)
        {
            if(k) k--;
            if(rank[i]==1) continue;
            while(s[sa[rank[i]-1]+k]==s[i+k]) k++;
            height[rank[i]]=k;
        }
    }
    int pmn[maxn][maxd],smn[maxn][maxd],Len[maxn];
    void Init(int n)
    {
        s[n+1]=0;
        Get_SA(n,30);
        Get_Height(n);

        for(int i=1;(1<<i)<=n;i++) Len[1<<i]=i;
        for(int i=1;i<=n;i++) if(!Len[i]) Len[i]=Len[i-1];

        for(int i=1;i<=n;i++) pmn[i][0]=height[i],smn[i][0]=height[i];
        for(int d=1;d<maxd;d++)
        {
            for(int i=(1<<d);i<=n;i++)
                pmn[i][d]=min(pmn[i][d-1],pmn[i-(1<<d-1)][d-1]);
            for(int i=1;i+(1<<d)-1<=n;i++)
                smn[i][d]=min(smn[i][d-1],smn[i+(1<<d-1)][d-1]);
        }
    }
    int q(int l,int r)
    {
        l=rank[l],r=rank[r];
        if(l>r) swap(l,r);
        l++;
        int len=Len[r-l+1];
        return min(smn[l][len],pmn[r][len]);
    }
}sa1,sa2;

int n;
char str[maxn];

int fl[maxn],fr[maxn],gl[maxn],gr[maxn];

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    int tcase; scanf("%d",&tcase);
    while(tcase--)
    {
        scanf("%s",str); n=strlen(str);

        for(int i=1;i<=n;i++) sa1.s[i]=str[i-1]-'a'+1;
        sa1.Init(n);
        for(int i=1;i<=n;i++) sa2.s[i]=str[n-i]-'a'+1;
        sa2.Init(n);

        for(int i=1;i<=n;i++) fl[i]=fr[i]=0;

        for(int L=1;(L<<1)<n;L++)
        {
            for(int i=1;i<=n;i+=L)
            {
                int j=i+L; if(j>n) break;
                int tp=min(sa2.q(n-i+1,n-j+1),L),ts=min(sa1.q(i,j),L);
                if(tp+ts-1>=L)
                {
                    int head=i-tp+1,tail=i+ts-L;
                    fr[head]++,fr[tail+1]--;
                    head+=L,tail+=L;
                    fl[head+L-1]++,fl[tail+L]--;
                }
            }
        }
        for(int i=1;i<=n;i++) gl[i]=gl[i-1]+fl[i],gr[i]=gr[i-1]+fr[i];

        ll ans=0;
        for(int i=1;i<n;i++) ans+=(ll)gl[i]*gr[i+1];
        printf("%lld\n",ans);
    }

    return 0;
}

D1T2网格
细节爆炸…
首先答案显然只会是-1,0,1,2
跳蚤个数<=1或者=2且挨着时就是-1
将所有蛐蛐外围两圈(八联通的八联通)的跳蚤建进一个只有跳蚤的新图里,四联通建边,若有某个蛐蛐四联通块挨着的某两个跳蚤不在一个联通块答案就是0
然后在这个建出来的新图里跑点双,看是否存在某个蛐蛐,其八联通的跳蚤中有某个跳蚤是割点,有答案就是1,否则就是2

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void down(int &a,const int &b){if(a>b)a=b;}
//const int dx1[] = {-1,-1,-1,0,0,1,1,1};
//const int dy1[] = {-1,0,1,-1,1,-1,0,1};
int dx[24],dy[24];
const int dx4[]={-1,0,1,0};
const int dy4[]={0,1,0,-1};
const int dx8[]={-1,-1,-1,0,0,1,1,1};
const int dy8[]={-1,0,1,-1,1,-1,0,1};

const int maxn = 110000;
const int hashmod = 2333337;

int n,m; ll N;
struct point
{
    int x,y;
    void Read(){ read(x),read(y); }
    int hash(){return ((ll)x*23333+(ll)y*100007)%hashmod;}
    int con4(const point p) { return abs(x-p.x)+abs(y-p.y)==1; }
    int ok() { return x>0&&y>0&&x<=n&&y<=m; }
}p[maxn],np[maxn*24]; int pn;

struct Hash_Table
{
    int cnt,tot;
    int xi[hashmod*5],yi[hashmod*5],id[hashmod*5],nex[hashmod*5];
    void init()
    {
        for(int i=0;i<hashmod;i++) xi[i]=0;
        cnt=hashmod-1; tot=0;
    }
    void ins(point tx)
    {
        int x=tx.hash();
        if(!xi[x]) { xi[x]=tx.x,yi[x]=tx.y,np[id[x]=++tot]=tx,nex[x]=-1; return; }

        int la; for(;x!=-1;la=x,x=nex[x]);
        nex[la]=++cnt;
        xi[cnt]=tx.x,yi[cnt]=tx.y,np[id[cnt]=++tot]=tx,nex[cnt]=-1;
    }
    int find_(point tx)
    {
        int x=tx.hash();
        if(!xi[x]) return -1;
        for(;x!=-1;x=nex[x]) if(xi[x]==tx.x&&yi[x]==tx.y)
            return id[x];
        return -1;
    }
}h;

namespace Graph
{
    int n;
    struct edge{int y,nex;}a[maxn*24*4]; int len,fir[maxn*24];
    void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}
    int dfn[maxn*24],low[maxn*24],dfi;
    int mark[maxn*24],bel[maxn*24],cnt;
    void init(int newn)
    {
        while(n) dfn[n]=bel[n]=mark[n]=fir[n]=0,n--;
        len=dfi=cnt=0; n=newn;
    }
    void build()
    {
        init(h.tot);
        for(int i=1;i<=pn;i++) for(int j=0;j<4;j++)
        {
            point temp=(point){np[i].x+dx4[j],np[i].y+dy4[j]};
            int y=h.find_(temp);
            if(y==-1||y>pn) continue;
            ins(i,y);
        }
        for(int i=pn+1;i<=n;i++) for(int j=0;j<4;j++)
        {
            point temp=(point){np[i].x+dx4[j],np[i].y+dy4[j]};
            int y=h.find_(temp);
            if(y<=pn) continue;
            ins(i,y);
        }
    }
    void tarjan(const int x,const int fa)
    {
        bel[x]=cnt;
        dfn[x]=low[x]=++dfi; int di=0;
        for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa)
        {
            if(!dfn[y])
            {
                di++;
                tarjan(y,x),down(low[x],low[y]);
                if(low[y]>=dfn[x]) mark[x]=1;
            }
            else down(low[x],dfn[y]);
        }
        if(!fa&&di==1) mark[x]=0;
    }
    int las[maxn];
    int main()
    {
        build();
        for(int i=1;i<=n;i++) if(!dfn[i])
            ++cnt,tarjan(i,0);
        if(N<=1||(N==2&&bel[pn+1]==bel[pn+2])) return -1;

        for(int i=1;i<=pn;i++) las[i]=0;
        int ok1=0;
        for(int i=1;i<=pn;i++) 
        {
            for(int j=0;j<4;j++)
            {
                point temp=(point){p[i].x+dx4[j],p[i].y+dy4[j]};
                int y=h.find_(temp); if(y<=pn) continue;

                if(las[bel[i]]&&las[bel[i]]!=bel[y]) return 0;
                las[bel[i]]=bel[y];
            }
            for(int j=0;j<8;j++)
            {
                point temp=(point){p[i].x+dx8[j],p[i].y+dy8[j]};
                int y=h.find_(temp); if(y<=pn) continue;

                ok1|=mark[y];
            }
        }
        return 2-ok1;
    }
}

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    int dxn=0;
    for(int i=-2;i<=2;i++) for(int j=-2;j<=2;j++) if(i||j)
    {
        dx[dxn]=i,dy[dxn]=j;
        dxn++;
    }

    int tcase; read(tcase);
    while(tcase--)
    {
        read(n); read(m); read(pn); N=(ll)n*m-pn;
        if(!pn)
        {
            if(N<=2) puts("-1");
            else if(n==1||m==1) puts("1");
            else puts("2");
            continue;
        }

        for(int i=1;i<=pn;i++) p[i].Read();

        h.init();
        for(int i=1;i<=pn;i++) h.ins(p[i]);
        for(int i=1;i<=pn;i++) for(int j=0;j<24;j++)
        {
            point temp=(point){p[i].x+dx[j],p[i].y+dy[j]};
            if(!temp.ok()) continue;
            if(h.find_(temp)==-1) h.ins(temp);
        }

        int ans=Graph::main();
        if(n==1||m==1) ans=min(1,ans);
        printf("%d\n",ans);
    }

    return 0;
}

D1T3循环之美
之前写过了:
https://blog.csdn.net/l_0_forever_lf/article/details/79494188

D2T1区间
将区间按照长度排序,维护双指针 i , j ,将 [ i , j ] 内的线段区间+1,如果有某个点被覆盖次数 >= m 就一定存在一组选 m 个区间有公共交集的解, l e n [ j ] l e n [ i ] 就可以贡献到答案, t w o p o i n t e r s 扫一遍, O ( n l o g n )

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define lc (x<<1)
#define rc (x<<1|1)
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 1010000;

int n,m;
struct node
{
    int l,r,len;
    void Read() { read(l),read(r);len=r-l; }
    friend inline bool operator <(const node x,const node y){return x.len<y.len;}
}a[maxn]; int cnt;

struct segment
{
    int seg[maxn<<2],flag[maxn<<2];
    int lx,rx,c;
    void pushdown(const int x)
    {
        if(!flag[x]) return;
        int fl=flag[x]; flag[x]=0;
        seg[lc]+=fl,flag[lc]+=fl;
        seg[rc]+=fl,flag[rc]+=fl;
    }
    void pushup(const int x){ seg[x]=max(seg[lc],seg[rc]); }
    void upd(const int x,const int l,const int r)
    {
        if(rx<l||r<lx) return;
        if(lx<=l&&r<=rx) { seg[x]+=c,flag[x]+=c;return; }
        pushdown(x);
        int mid=(l+r)>>1;
        upd(lc,l,mid); upd(rc,mid+1,r);
        pushup(x);
    }
    int q(){ return seg[1]; }
}seg;

namespace Trans
{
    struct data
    {
        int x; int *i;
        data(){}
        data(int _x,int *_i){x=_x;i=_i;}
        friend inline bool operator <(const data x,const data y){return x.x<y.x;}
    }b[maxn]; int bn;
    void main()
    {
        for(int i=1;i<=n;i++)
        {
            b[++bn]=data(a[i].l,&a[i].l);
            b[++bn]=data(a[i].r,&a[i].r);
        }
        sort(b+1,b+bn+1);
        for(int i=1;i<=bn;i++)
        {
            if(i==1||b[i].x!=b[i-1].x) ++cnt;
            (*b[i].i)=cnt;
        }
    }
}

int solve()
{
    int l=1,r=0,ans=-1;
    for(;r<=n;r++)
    {
        seg.lx=a[r].l,seg.rx=a[r].r,seg.c=1,seg.upd(1,1,cnt);
        while(l<=r&&seg.q()>=m)
        {
            if(ans==-1||ans>a[r].len-a[l].len) ans=a[r].len-a[l].len;
            seg.lx=a[l].l,seg.rx=a[l].r,seg.c=-1,seg.upd(1,1,cnt);
            l++;
        }
    }
    return ans;
}

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    read(n); read(m);
    int l=INT_MAX,r=INT_MIN;
    for(int i=1;i<=n;i++) a[i].Read(),l=min(l,a[i].len),r=max(r,a[i].len);
    Trans::main();

    sort(a+1,a+n+1);
    printf("%d\n",solve());

    return 0;
}

D2T2国王饮水记
证了大概有10个结论?
通过若干辅助结论,最终推出几个比较重要的结论:
排完序后k次连通一定是挨着的k个区间且长度递减,长度>1的区间数量<=14。
证明不会

有了这些就可以直接dp了, f [ i ] [ j ] 表示前 i 个点,用了 j 次连通
f [ i ] [ j ] = m a x ( f [ k ] [ j 1 ] + s u m i s u m k i k + 1 )
f [ i ] [ j ] = m a x ( s u m [ i ] ( s u m [ k ] f [ k ] [ j 1 ] ) i ( k 1 ) )
画在二维平面就是求最大斜率
维护 s u m i f [ i ] [ j ] i 1 的下凸壳,转移有决策单调性,于是将dp优化到14n
有个trick是前面的14次连通不用高精度小数,直接用long double dp,dp出每个状态的决策点,从哪里转移过来,找到最优解后再用高精度小数计算答案

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

// ---------- decimal lib start ----------

const int PREC = 4100;

class Decimal {
    public:
        Decimal();
        Decimal(const std::string &s);
        Decimal(const char *s);
        Decimal(int x);
        Decimal(long long x);
        Decimal(double x);

        bool is_zero() const;

        // p (p > 0) is the number of digits after the decimal point
        std::string to_string(int p) const;
        double to_double() const;

        friend Decimal operator + (const Decimal &a, const Decimal &b);
        friend Decimal operator + (const Decimal &a, int x);
        friend Decimal operator + (int x, const Decimal &a);
        friend Decimal operator + (const Decimal &a, long long x);
        friend Decimal operator + (long long x, const Decimal &a);
        friend Decimal operator + (const Decimal &a, double x);
        friend Decimal operator + (double x, const Decimal &a);

        friend Decimal operator - (const Decimal &a, const Decimal &b);
        friend Decimal operator - (const Decimal &a, int x);
        friend Decimal operator - (int x, const Decimal &a);
        friend Decimal operator - (const Decimal &a, long long x);
        friend Decimal operator - (long long x, const Decimal &a);
        friend Decimal operator - (const Decimal &a, double x);
        friend Decimal operator - (double x, const Decimal &a);

        friend Decimal operator * (const Decimal &a, int x);
        friend Decimal operator * (int x, const Decimal &a);

        friend Decimal operator / (const Decimal &a, int x);

        friend bool operator < (const Decimal &a, const Decimal &b);
        friend bool operator > (const Decimal &a, const Decimal &b);
        friend bool operator <= (const Decimal &a, const Decimal &b);
        friend bool operator >= (const Decimal &a, const Decimal &b);
        friend bool operator == (const Decimal &a, const Decimal &b);
        friend bool operator != (const Decimal &a, const Decimal &b);

        Decimal & operator += (int x);
        Decimal & operator += (long long x);
        Decimal & operator += (double x);
        Decimal & operator += (const Decimal &b);

        Decimal & operator -= (int x);
        Decimal & operator -= (long long x);
        Decimal & operator -= (double x);
        Decimal & operator -= (const Decimal &b);

        Decimal & operator *= (int x);

        Decimal & operator /= (int x);

        friend Decimal operator - (const Decimal &a);

        // These can't be called
        friend Decimal operator * (const Decimal &a, double x);
        friend Decimal operator * (double x, const Decimal &a);
        friend Decimal operator / (const Decimal &a, double x);
        Decimal & operator *= (double x);
        Decimal & operator /= (double x);

    private:
        static const int len = PREC / 9 + 1;
        static const int mo = 1000000000;

        static void append_to_string(std::string &s, long long x);

        bool is_neg;
        long long integer;
        int data[len];

        void init_zero();
        void init(const char *s);
};

Decimal::Decimal() {
    this->init_zero();
}

Decimal::Decimal(const char *s) {
    this->init(s);
}

Decimal::Decimal(const std::string &s) {
    this->init(s.c_str());
}

Decimal::Decimal(int x) {
    this->init_zero();

    if (x < 0) {
        is_neg = true;
        x = -x;
    }

    integer = x;
}

Decimal::Decimal(long long x) {
    this->init_zero();

    if (x < 0) {
        is_neg = true;
        x = -x;
    }

    integer = x;
}

Decimal::Decimal(double x) {
    this->init_zero();

    if (x < 0) {
        is_neg = true;
        x = -x;
    }

    integer = (long long)x;
    x -= integer;

    for (int i = 0; i < len; i++) {
        x *= mo;
        if (x < 0) x = 0;
        data[i] = (int)x;
        x -= data[i];
    }
}

void Decimal::init_zero() {
    is_neg = false;
    integer = 0;
    memset(data, 0, len * sizeof(int));
}

bool Decimal::is_zero() const {
    if (integer) return false;
    for (int i = 0; i < len; i++) {
        if (data[i]) return false;
    }
    return true;
}

void Decimal::init(const char *s) {
    this->init_zero();

    is_neg = false;
    integer = 0;

    // find the first digit or the negative sign
    while (*s != 0) {
        if (*s == '-') {
            is_neg = true;
            ++s;
            break;
        } else if (*s >= 48 && *s <= 57) {
            break;
        }
        ++s;
    }

    // read the integer part
    while (*s >= 48 && *s <= 57) {
        integer = integer * 10 + *s - 48;
        ++s;
    }

    // read the decimal part
    if (*s == '.') {
        int pos = 0;
        int x = mo / 10;

        ++s;
        while (pos < len && *s >= 48 && *s <= 57) {
            data[pos] += (*s - 48) * x;
            ++s;
            x /= 10;
            if (x == 0) {
                ++pos;
                x = mo / 10;
            }
        }
    }
}

void Decimal::append_to_string(std::string &s, long long x) {
    if (x == 0) {
        s.append(1, 48);
        return;
    }

    char _[30];
    int cnt = 0;
    while (x) {
        _[cnt++] = x % 10;
        x /= 10;
    }
    while (cnt--) {
        s.append(1, _[cnt] + 48);
    }
}

std::string Decimal::to_string(int p) const {
    std::string ret;

    if (is_neg && !this->is_zero()) {
        ret = "-";
    }

    append_to_string(ret, this->integer);

    ret.append(1, '.');

    for (int i = 0; i < len; i++) {
        // append data[i] as "%09d"
        int x = mo / 10;
        int tmp = data[i];
        while (x) {
            ret.append(1, 48 + tmp / x);
            tmp %= x;
            x /= 10;
            if (--p == 0) {
                break;
            }
        }
        if (p == 0) break;
    }

    if (p > 0) {
        ret.append(p, '0');
    }

    return ret;
}

double Decimal::to_double() const {
    double ret = integer;

    double k = 1.0;
    for (int i = 0; i < len; i++) {
        k /= mo;
        ret += k * data[i];
    }

    if (is_neg) {
        ret = -ret;
    }

    return ret;
}

bool operator < (const Decimal &a, const Decimal &b) {
    if (a.is_neg != b.is_neg) {
        return a.is_neg && (!a.is_zero() || !b.is_zero());
    } else if (!a.is_neg) {
        // a, b >= 0
        if (a.integer != b.integer) {
            return a.integer < b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] < b.data[i];
            }
        }
        return false;
    } else {
        // a, b <= 0
        if (a.integer != b.integer) {
            return a.integer > b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] > b.data[i];
            }
        }
        return false;
    }
}

bool operator > (const Decimal &a, const Decimal &b) {
    if (a.is_neg != b.is_neg) {
        return !a.is_neg && (!a.is_zero() || !b.is_zero());
    } else if (!a.is_neg) {
        // a, b >= 0
        if (a.integer != b.integer) {
            return a.integer > b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] > b.data[i];
            }
        }
        return false;
    } else {
        // a, b <= 0
        if (a.integer != b.integer) {
            return a.integer < b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] < b.data[i];
            }
        }
        return false;
    }
}

bool operator <= (const Decimal &a, const Decimal &b) {
    if (a.is_neg != b.is_neg) {
        return a.is_neg || (a.is_zero() && b.is_zero());
    } else if (!a.is_neg) {
        // a, b >= 0
        if (a.integer != b.integer) {
            return a.integer < b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] < b.data[i];
            }
        }
        return true;
    } else {
        // a, b <= 0
        if (a.integer != b.integer) {
            return a.integer > b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] > b.data[i];
            }
        }
        return true;
    }
}

bool operator >= (const Decimal &a, const Decimal &b) {
    if (a.is_neg != b.is_neg) {
        return !a.is_neg || (a.is_zero() && b.is_zero());
    } else if (!a.is_neg) {
        // a, b >= 0
        if (a.integer != b.integer) {
            return a.integer > b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] > b.data[i];
            }
        }
        return true;
    } else {
        // a, b <= 0
        if (a.integer != b.integer) {
            return a.integer < b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] < b.data[i];
            }
        }
        return true;
    }
}

bool operator == (const Decimal &a, const Decimal &b) {
    if (a.is_zero() && b.is_zero()) return true;
    if (a.is_neg != b.is_neg) return false;
    if (a.integer != b.integer) return false;
    for (int i = 0; i < Decimal::len; i++) {
        if (a.data[i] != b.data[i]) return false;
    }
    return true;
}

bool operator != (const Decimal &a, const Decimal &b) {
    return !(a == b);
}

Decimal & Decimal::operator += (long long x) {
    if (!is_neg) {
        if (integer + x >= 0) {
            integer += x;
        } else {
            bool last = false;
            for (int i = len - 1; i >= 0; i--) {
                if (last || data[i]) {
                    data[i] = mo - data[i] - last;
                    last = true;
                } else {
                    last = false;
                }
            }
            integer = -x - integer - last;
            is_neg = true;
        }
    } else {
        if (integer - x >= 0) {
            integer -= x;
        } else {
            bool last = false;
            for (int i = len - 1; i >= 0; i--) {
                if (last || data[i]) {
                    data[i] = mo - data[i] - last;
                    last = true;
                } else {
                    last = false;
                }
            }
            integer = x - integer - last;
            is_neg = false;
        }
    }
    return *this;
}

Decimal & Decimal::operator += (int x) {
    return *this += (long long)x;
}

Decimal & Decimal::operator -= (int x) {
    return *this += (long long)-x;
}

Decimal & Decimal::operator -= (long long x) {
    return *this += -x;
}

Decimal & Decimal::operator /= (int x) {
    if (x < 0) {
        is_neg ^= 1;
        x = -x;
    }

    int last = integer % x;
    integer /= x;

    for (int i = 0; i < len; i++) {
        long long tmp = 1LL * last * mo + data[i];
        data[i] = tmp / x;
        last = tmp - 1LL * data[i] * x;
    }

    if (is_neg && integer == 0) {
        int i;
        for (i = 0; i < len; i++) {
            if (data[i] != 0) {
                break;
            }
        }
        if (i == len) {
            is_neg = false;
        }
    }

    return *this;
}

Decimal & Decimal::operator *= (int x) {
    if (x < 0) {
        is_neg ^= 1;
        x = -x;
    } else if (x == 0) {
        init_zero();
        return *this;
    }

    int last = 0;
    for (int i = len - 1; i >= 0; i--) {
        long long tmp = 1LL * data[i] * x + last;
        last = tmp / mo;
        data[i] = tmp - 1LL * last * mo;
    }
    integer = integer * x + last;

    return *this;
}

Decimal operator - (const Decimal &a) {
    Decimal ret = a;
    // -0 = 0
    if (!ret.is_neg && ret.integer == 0) {
        int i;
        for (i = 0; i < Decimal::len; i++) {
            if (ret.data[i] != 0) break;
        }
        if (i < Decimal::len) {
            ret.is_neg = true;
        }
    } else {
        ret.is_neg ^= 1;
    }
    return ret;
}

Decimal operator + (const Decimal &a, int x) {
    Decimal ret = a;
    return ret += x;
}

Decimal operator + (int x, const Decimal &a) {
    Decimal ret = a;
    return ret += x;
}

Decimal operator + (const Decimal &a, long long x) {
    Decimal ret = a;
    return ret += x;
}

Decimal operator + (long long x, const Decimal &a) {
    Decimal ret = a;
    return ret += x;
}

Decimal operator - (const Decimal &a, int x) {
    Decimal ret = a;
    return ret -= x;
}

Decimal operator - (int x, const Decimal &a) {
    return -(a - x);
}

Decimal operator - (const Decimal &a, long long x) {
    Decimal ret = a;
    return ret -= x;
}

Decimal operator - (long long x, const Decimal &a) {
    return -(a - x);
}

Decimal operator * (const Decimal &a, int x) {
    Decimal ret = a;
    return ret *= x;
}

Decimal operator * (int x, const Decimal &a) {
    Decimal ret = a;
    return ret *= x;
}

Decimal operator / (const Decimal &a, int x) {
    Decimal ret = a;
    return ret /= x;
}

Decimal operator + (const Decimal &a, const Decimal &b) {
    if (a.is_neg == b.is_neg) {
        Decimal ret = a;
        bool last = false;
        for (int i = Decimal::len - 1; i >= 0; i--) {
            ret.data[i] += b.data[i] + last;
            if (ret.data[i] >= Decimal::mo) {
                ret.data[i] -= Decimal::mo;
                last = true;
            } else {
                last = false;
            }
        }
        ret.integer += b.integer + last;
        return ret;
    } else if (!a.is_neg) {
        // a - |b|
        return a - -b;
    } else {
        // b - |a|
        return b - -a;
    }
}

Decimal operator - (const Decimal &a, const Decimal &b) {
    if (!a.is_neg && !b.is_neg) {
        if (a >= b) {
            Decimal ret = a;
            bool last = false;
            for (int i = Decimal::len - 1; i >= 0; i--) {
                ret.data[i] -= b.data[i] + last;
                if (ret.data[i] < 0) {
                    ret.data[i] += Decimal::mo;
                    last = true;
                } else {
                    last = false;
                }
            }
            ret.integer -= b.integer + last;
            return ret;
        } else {
            Decimal ret = b;
            bool last = false;
            for (int i = Decimal::len - 1; i >= 0; i--) {
                ret.data[i] -= a.data[i] + last;
                if (ret.data[i] < 0) {
                    ret.data[i] += Decimal::mo;
                    last = true;
                } else {
                    last = false;
                }
            }
            ret.integer -= a.integer + last;
            ret.is_neg = true;
            return ret;
        }
    } else if (a.is_neg && b.is_neg) {
        // a - b = (-b) - (-a)
        return -b - -a;
    } else if (a.is_neg) {
        // -|a| - b
        return -(-a + b);
    } else {
        // a - -|b|
        return a + -b;
    }
}

Decimal operator + (const Decimal &a, double x) {
    return a + Decimal(x);
}

Decimal operator + (double x, const Decimal &a) {
    return Decimal(x) + a;
}

Decimal operator - (const Decimal &a, double x) {
    return a - Decimal(x);
}

Decimal operator - (double x, const Decimal &a) {
    return Decimal(x) - a;
}

Decimal & Decimal::operator += (double x) {
    *this = *this + Decimal(x);
    return *this;
}

Decimal & Decimal::operator -= (double x) {
    *this = *this - Decimal(x);
    return *this;
}

Decimal & Decimal::operator += (const Decimal &b) {
    *this = *this + b;
    return *this;
}

Decimal & Decimal::operator -= (const Decimal &b) {
    *this = *this - b;
    return *this;
}

// ---------- decimal lib end ----------

#define ld long double

const int maxn = 8100;

int n,K,P;
int a[maxn],sum[maxn];

struct point
{
    ld x,y;
    int i;
    friend inline point operator -(const point x,const point y){return (point){x.x-y.x,x.y-y.y};}
    friend inline ld operator *(const point x,const point y){return x.x*y.y-x.y*y.x;}
}q[maxn]; int head,tail,las;
ld f[maxn][15]; int pre[maxn][15];
Decimal g[15];
void dp()
{
    for(int i=1;i<=n;i++) f[i][0]=a[1];
    for(int k=1;k<=14&&k<=K;k++)
    {
        head=1,tail=0; las=1;
        for(int i=1;i<=n;i++)
        {
            if(head<=tail)
            {
                point temp=(point){(ld)i,(ld)sum[i]};
                while(las<tail&&(q[las+1]-q[las])*(temp-q[las+1])>0) las++;
                int j=q[las].i;
                f[i][k]=(f[j][k-1]+sum[i]-sum[j])/(i-j+1);
                pre[i][k]=j;
            }
            if(i>=k)
            {
                point temp=(point){(ld)i-1,(ld)sum[i]-f[i][k-1],i};
                while(head<tail&&(q[tail]-q[tail-1])*(temp-q[tail])<=0) tail--;
                q[++tail]=temp;
            }
        }
    }
    for(int k=0;k<=14&&k<=K;k++)
    {
        g[k]=(double)f[n-(K-k)][k];
        for(int i=n-(K-k)+1;i<=n;i++) g[k]=(g[k]+a[i])/2;
    }
}

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    scanf("%d%d%d",&n,&K,&P);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]<a[1]) i--,n--;
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
    K=min(K,n-1);

    dp();
    int ansk=0;
    for(int k=1;k<=14&&k<=K;k++) if(g[k]>g[ansk]) ansk=k;
    Decimal ans=0,p=1;
    for(int i=n;i>n-(K-ansk);i--)
    {
        p/=2;
        ans+=p*a[i];
    }
    for(int i=n-(K-ansk),k=ansk;k;i=pre[i][k],k--)
    {
        int j=pre[i][k];
        p/=i-j+1;
        ans+=p*(sum[i]-sum[j]);
    }
    ans+=p*a[1];
    cout<<ans.to_string(2*P-1)<<endl;

    return 0;
}

D2T3旷野大计算
人类智慧题
我果然没有耐心刚题答
药丸

猜你喜欢

转载自blog.csdn.net/l_0_forever_lf/article/details/80711315
今日推荐