D1T1优秀的拆分
枚举AABB中AB的交界处,其实就是要计算每个位置AA的数量,算这个东西有个经典套路:
枚举A的长度,每A个字符设置一个关键点,任意一个A一定覆盖且仅覆盖1个关键点,枚举相邻的两个关键点,后缀数组上st表O(1) lcp求他们往左往右匹配长度
O(nlogn)
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
,将
[i,j]
[
i
,
j
]
内的线段区间+1,如果有某个点被覆盖次数
>=m
>=
m
就一定存在一组选
m
m
个区间有公共交集的解,就可以贡献到答案,
twopointers
t
w
o
p
o
i
n
t
e
r
s
扫一遍,
O(nlogn)
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]
f
[
i
]
[
j
]
表示前
i
i
个点,用了次连通
f[i][j]=max(f[k][j−1]+sumi−sumki−k+1)
f
[
i
]
[
j
]
=
m
a
x
(
f
[
k
]
[
j
−
1
]
+
s
u
m
i
−
s
u
m
k
i
−
k
+
1
)
f[i][j]=max(sum[i]−(sum[k]−f[k][j−1])i−(k−1))
f
[
i
]
[
j
]
=
m
a
x
(
s
u
m
[
i
]
−
(
s
u
m
[
k
]
−
f
[
k
]
[
j
−
1
]
)
i
−
(
k
−
1
)
)
画在二维平面就是求最大斜率
维护
sumi−f[i][j]i−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旷野大计算
人类智慧题
我果然没有耐心刚题答
药丸