2019雅礼集训day1 题解

T1 three

bzoj4543原题
题解


T2 permutation

2019雅礼集训day1 题解_第1张图片
n , m ≤ 1 0 5 , A i ≤ 1 0 8 n,m\leq 10^5,A_i\leq 10^8 n,m105,Ai108

一道比较巧妙的题:

首先将 A A A按升序排序,最优的答案就是 ∑ i = 1 n ( n − i + 1 ) × A i \sum\limits_{i=1}^n (n-i+1)\times A_i i=1n(ni+1)×Ai

每个操作后的排列可以用一系列二元组 ( u , v ) (u,v) (u,v)表达出来(且这个表达是唯一的)(满足 u u u单调递增):
( u , v ) (u,v) (u,v)表示将排列 [ u − v , u ] [u-v,u] [uv,u]循环右移一位,其代价 g ( u , v ) = ∑ i = 1 v A u − A u − i g(u,v)=\sum\limits_{i=1}^vA_u-A_{u-i} g(u,v)=i=1vAuAui

显然 g ( u , v ) ≤ g ( u , v + 1 ) g(u,v)\leq g(u,v+1) g(u,v)g(u,v+1),由增量算法向外拓展 k − 1 k-1 k1步就得到了前 k k k小的值。

考虑主席树维护 g ( u , v ) ( 1 ≤ u ≤ n ) g(u,v)(1\leq u\leq n) g(u,v)(1un),初始化所有 v = 1 v=1 v=1,每次取最小的 g g g拓展。

拓展后可以得到新的两种状态:

  • g ( u , v ) → g ( u , v + 1 ) g(u,v)\rightarrow g(u,v+1) g(u,v)g(u,v+1),将对应位置值改一下即可。
  • [ u − v , u ] [u-v,u] [uv,u]循环右移,并删去区间 [ 1 , u − v − 1 ] [1,u-v-1] [1,uv1],初始化现存所有位置 v = 1 v=1 v=1

时间复杂度 O ( ( n + k ) log ⁡ n ) O((n+k)\log n) O((n+k)logn)

代码比较有技巧性:

#include
#define mid (l+r>>1)
#define lc t[k].ls
#define rc t[k].rs
using namespace std;
const int N=1e5+10,M=2e7+10;
typedef long long ll;
const ll inf=1e18;

int n,m,a[N],num,cnt;

char cp;
inline void rd(int &x)
{
	cp=getchar();x=0;int f=0;
	for(;!isdigit(cp);cp=getchar()) if(cp=='-') f=1;
	for(;isdigit(cp);cp=getchar()) x=x*10+(cp^48);
	if(f) x=-x;
}

template<class T>void prit(T x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>=10) prit(x/10);
	putchar('0'+x%10);
}

struct P{int tg;ll v;bool operator<(const P&ky)const{return ky.v<v;};}tp;
priority_queue<P>que;

struct node{int ls,rs,u,v,s;ll g;}t[M];
struct Q{int nw,ori;ll ss;}q[N];

inline void build(int &k,int l,int r)
{
	t[(k=++cnt)].s=r-l+1;
	if(l==r) return;
	build(lc,l,mid);build(rc,mid+1,r);
}

inline void pu(int k)
{
	if(t[lc].g<t[rc].g)
	  t[k].u=t[lc].u,t[k].v=t[lc].v,t[k].g=t[lc].g;
	else t[k].u=t[rc].u+t[lc].s,t[k].v=t[rc].v,t[k].g=t[rc].g;
	t[k].s=t[lc].s+t[rc].s;
}

void ins(int &k,int pos,ll v)
{
	t[++cnt]=t[k];k=cnt;
	if((!lc)&&(!rc)){
		t[k].u=t[k].s=1;
		t[k].v++;t[k].g+=v;
		return;
	}
	t[lc].s>=pos?ins(lc,pos,v):ins(rc,pos-t[lc].s,v);
	pu(k);
}

void chg(int &k,int pos,ll v,int exi)
{
	t[++cnt]=t[k];k=cnt;
	if((!lc)&&(!rc)){t[k].g=v;t[k].u=t[k].s=exi;return;}
	t[lc].s>=pos?chg(lc,pos,v,exi):chg(rc,pos-t[lc].s,v,exi);
	pu(k);
}

void del(int &k,int pos)
{
	if(!pos) return;
	t[++cnt]=t[k];k=cnt;
	if(t[lc].s>pos) del(lc,pos);
	else{pos-=t[lc].s;lc=0;del(rc,pos);}
	pu(k);
}

int ask(int k,int l,int r,int pos)
{
	if(l==r) return a[l];
	return t[lc].s>=pos?ask(lc,l,mid,pos):ask(rc,mid+1,r,pos-t[lc].s);
}

inline void upp(int cs)
{
	int x=q[cs].nw,u=t[x].u,v=t[x].v;
	q[++num].ss=q[cs].ss+t[x].g;
	q[num].nw=q[cs].ori;
	chg(q[num].nw,u,inf,0);
	if(u-v>1) del(q[num].nw,u-v-1);
	if(v<t[q[num].nw].s) chg(q[num].nw,v+1,ask(q[num].nw,1,n,v+1)-ask(q[num].nw,1,n,v),1);
	chg(q[num].nw,1,inf,1);q[num].ori=q[num].nw;
	que.push((P){num,q[num].ss+t[q[num].nw].g});
	if(u>v+1) ins(q[cs].nw,u,ask(q[cs].nw,1,n,u)-ask(q[cs].nw,1,n,u-v-1));
	else ins(q[cs].nw,u,inf);
	que.push((P){cs,q[cs].ss+t[q[cs].nw].g});
}

int main(){
	int i,j;
	rd(n);rd(m);t[0].g=inf;
	for(i=1;i<=n;++i) rd(a[i]);
	sort(a+1,a+n+1);
	build(q[0].nw,1,n);
	for(i=1;i<=n;++i){
		q[0].ss+=(ll)(n-i+1)*a[i];
		i>1?ins(q[0].nw,i,a[i]-a[i-1]):ins(q[0].nw,1,inf);
	}
	q[0].ori=q[0].nw;
	prit(q[0].ss);putchar('\n');
	que.push((P){0,q[0].ss+t[q[0].nw].g});
	for(m--;m;--m){
		tp=que.top();que.pop();
		prit(tp.v);putchar('\n');
		upp(tp.tg);
	}
	return 0;
}

T3 math

2019雅礼集训day1 题解_第2张图片
T ≤ 10 , n ≤ 1 0 9 , m ≤ 30 T\leq 10,n\leq 10^9,m\leq 30 T10,n109,m30

三角函数的巧妙运用(有一种化简三角函数的感觉(雾
f ( n , m ) = ∑ ( ∑ i = 1 m k i ) = n ∏ i = 1 m sin ⁡ ( k i ⋅ x ) f(n,m)=\sum\limits_{(\sum\limits_{i=1}^mk_i)=n}\prod\limits_{i=1}^m\sin(k_i·x) f(n,m)=(i=1mki)=ni=1msin(kix)

k = 1 k=1 k=1时,
f ( n − 1 , m − 1 ) × sin ⁡ ( x ) → f ( n , m ) f(n-1,m-1)\times\sin(x)\rightarrow f(n,m) f(n1,m1)×sin(x)f(n,m)
k > 1 k>1 k>1时,
f ( n − k , m − 1 ) × sin ⁡ ( k x ) → f ( n , m ) f(n-k,m-1)\times \sin(kx)\rightarrow f(n,m) f(nk,m1)×sin(kx)f(n,m)

sin ⁡ ( k x ) = sin ⁡ ( x + ( k − 1 ) x ) = sin ⁡ ( x ) cos ⁡ ( ( k − 1 ) x ) + cos ⁡ ( x ) sin ⁡ ( ( k − 1 ) x ) \sin(kx)=\sin(x+(k-1)x)=\sin(x)\cos((k-1)x)+\cos(x)\sin((k-1)x) sin(kx)=sin(x+(k1)x)=sin(x)cos((k1)x)+cos(x)sin((k1)x)


sin ⁡ ( x ) cos ⁡ ( k x ) = sin ⁡ ( x ) ( cos ⁡ ( x ) cos ⁡ ( ( k − 1 ) x ) − sin ⁡ ( x ) sin ⁡ ( ( k − 1 ) x ) ) \sin(x)\cos(kx)=\sin(x)(\cos(x)\cos((k-1)x)-\sin(x)\sin((k-1)x)) sin(x)cos(kx)=sin(x)(cos(x)cos((k1)x)sin(x)sin((k1)x))
   sin ⁡ ( x ) cos ⁡ ( x ) cos ⁡ ( ( k − 1 ) x ) + ( cos ⁡ 2 ( x ) − 1 ) sin ⁡ ( ( k − 1 ) x ) \qquad \qquad \qquad \quad \ \ \sin(x)\cos(x)\cos((k-1)x)+(\cos^2(x)-1)\sin((k-1)x)   sin(x)cos(x)cos((k1)x)+(cos2(x)1)sin((k1)x)
   cos ⁡ ( x ) ( sin ⁡ ( x ) cos ⁡ ( ( k − 1 ) x ) + cos ⁡ ( x ) sin ⁡ ( ( k − 1 ) x ) ) − sin ⁡ ( ( k − 1 ) x ) \qquad \qquad \qquad \quad \ \ \cos(x)(\sin(x)\cos((k-1)x)+\cos(x)\sin((k-1)x))-\sin((k-1)x)   cos(x)(sin(x)cos((k1)x)+cos(x)sin((k1)x))sin((k1)x)
   cos ⁡ ( x ) sin ⁡ ( k x ) − sin ⁡ ( ( k − 1 ) x ) \qquad \qquad \qquad \quad \ \ \cos(x)\sin(kx)-\sin((k-1)x)   cos(x)sin(kx)sin((k1)x)

sin ⁡ ( k x ) = 2 cos ⁡ ( x ) sin ⁡ ( ( k − 1 ) x ) − sin ⁡ ( ( k − 2 ) x ) \sin(kx)=2\cos(x)\sin((k-1)x)-\sin((k-2)x) sin(kx)=2cos(x)sin((k1)x)sin((k2)x)

2 cos ⁡ ( x ) f ( n − 1 , m ) − f ( n − 2 , m ) → f ( n , m ) 2\cos(x)f(n-1,m)-f(n-2,m)\rightarrow f(n,m) 2cos(x)f(n1,m)f(n2,m)f(n,m)

m m m这维很小可以进矩阵,所以按 n n n转移,转移方程:
f [ n ] [ m ] = 2 cos ⁡ ( x ) f [ n − 1 ] [ m ] − f [ n − 2 ] [ m ] + sin ⁡ ( x ) f [ n − 1 ] [ m − 1 ] f[n][m]=2\cos(x)f[n-1][m]-f[n-2][m]+\sin(x)f[n-1][m-1] f[n][m]=2cos(x)f[n1][m]f[n2][m]+sin(x)f[n1][m1]

矩乘优化后时间复杂度 O ( m 3 log ⁡ n ) O(m^3\log n) O(m3logn)

#include
using namespace std;
const int N=62;
typedef double db;

int tk,n,m,bs;db x;

struct mat{
	db a[N][N];
	mat operator *(const mat&ky){
		mat re;int i,j,k;db res;
		for(i=1;i<=bs;++i)
		 for(j=1;j<=bs;++j){		 	
		    for(res=0,k=1;k<=bs;++k) res+=a[i][k]*ky.a[k][j];
		    re.a[i][j]=res;
		 }
		return re;
	}
}A,B;

int main(){
	int i,j;db r,t;
	for(scanf("%d",&tk);tk;--tk){
		scanf("%d%d%lf",&m,&n,&x);bs=m<<1;
		memset(A.a,0,sizeof(A.a));memset(B.a,0,sizeof(B.a));
		r=2*cos(x);t=sin(x);
		for(i=m+1;i<=bs;++i){
			A.a[i-m][i]=-1;A.a[i][i-m]=1;A.a[i][i]=r;
			if(i<bs) A.a[i][i+1]=t;
		}
		B.a[1][1]=t;B.a[1][m+1]=sin(2*x);B.a[1][m+2]=t*t;
		for(n--;n;n>>=1,A=A*A) if(n&1) B=B*A;
		r=B.a[1][m];
		if(r>0) putchar('+');else r=-r,putchar('-');
		for(;r>=10.0;r/=10);for(;r<1;r*=10);
		printf("%d\n",(int)r);
	}
	return 0;
}

小结

全程打暴力。
T1经典dp&原题竟然没有做出来。
T2太巧妙了orz只会打暴力。
T3一直都没读懂题意。

你可能感兴趣的:(主席树,矩阵加速DP,2019YALIWC)