$$ \newcommand{\seq}[2]{{#1}_{1},{#1}_{2},\cdots,{#1}_{#2}} \newcommand{\num}[1]{1,2,\cdots,#1} \newcommand{\stra}[2]{\begin{bmatrix}#1 \\ #2\end{bmatrix}} \newcommand{\strb}[2]{\begin{Bmatrix}#1 \\ #2\end{Bmatrix}} \newcommand{\dw}[1]{\underline{#1}} \newcommand{\up}[1]{\overline{#1}} $$

Codeforces 515

515 C

题意

定义一个函数 \(F(x)\) ,举例: \(F(123450)=1!*2!*3!*4!*5!*0!\)
现在给你一个数 \(a\) ,最多 \(15\) 位,求最大的数 \(x\) ,使得:

  • \(x\) 中不包含 \(0\)\(1\) 数码;
  • \(F(x)=F(a)\)

Examples

input
4
1234
output
33222
input
3
555
output
555

首先,要尽量把大数的阶乘分解成若干个小数的阶乘。
其次,各个数码应该从大到小排列,这样才最优。
再次,

\[4!=3!*(2!)^2 \]

\[6!=5!*3! \]

\[8!=7!*(2!)^3 \]

\[9!=7!*(3!)^2*2! \]

Code

#include<bits/stdc++.h>
#define maxn 103
using namespace std;
template<typename tp>
void read(tp& x){
	x=0;
	char c=getchar();
	bool sgn=0;
	while((c<'0'||c>'9')&&c!='-')c=getchar();
	if(c=='-')sgn=1,c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
	if(sgn)x=-x;
}
template<typename tp>
void write(tp x){
	if(x<0)putchar('-'),write(-x);
	else{
		if(x>=10)write(x/10);
		putchar(x%10+'0');
	}
}
int a[11],b[17],n;
char c[17];
int main(){
	read(n);
	scanf("%s",c);
	for(int i=1;i<=n;i++){
		b[i]=c[i-1]-'0';
		a[b[i]]++;
	}
	for(int i=9;i>=2;i--){
		if(i==9)a[7]+=a[9],a[3]+=a[9]*2,a[2]+=a[9],a[9]=0;
		if(i==8)a[7]+=a[8],a[2]+=a[8]*3,a[8]=0;
		if(i==6)a[5]+=a[6],a[3]+=a[6],a[6]=0;
		if(i==4)a[3]+=a[4],a[2]+=a[4]*2,a[4]=0;
	}
	for(int i=1;i<=a[7];i++)putchar('7');
	for(int i=1;i<=a[5];i++)putchar('5');
	for(int i=1;i<=a[3];i++)putchar('3');
	for(int i=1;i<=a[2];i++)putchar('2');
	return 0;
}

515 E

题意

\(n\) 棵树围成一个环,现在有 \(m\) 组询问,每组包含两个数 \(a_i,b_i\) ,表示 \(a_i-b_i\) 的所有树被占领,你不能经过,现在告诉你每两棵树之间的距离 \(d_i\) (表示 \(i\)\(i+1\) 的距离)、树的高度 \(h_i\) ,你能获得的收益为 \(2*(h_i+h_j)+\sum_{k为i-j的路径上所有的树}d_k\) ,现在对于每个询问,请你输出最大的收益。 \((n,m\le 10^5)\)

Examples

input
5 3
2 2 2 2 2
3 5 2 1 4
1 3
2 2
4 5
output
12
16
18
input
3 3
5 1 4
5 1 4
3 3
2 2
1 1
output
17
22
11

首先,处理环的一般方式:将数组扩大一倍
然后,问题变为求一段区间的最大子段和,可以用线段树维护。
方法:每个节点维护六个值。
\(lmx\) 表示区间中最大 \(d_i\) 子段和(有个端点在区间左端点,不包括端点的 \(h_i\)), \(rmx\) 表示区间中最大 \(d_i\) 子段和(有个端点在区间右端点,不包括端点的 \(h_i\)),\(mx\) 表示区间中最大 \(d_i\) 子段和(不包括端点的 \(h_i\)); \(lr,rr,r\) 与上述变量意义相同,但包括端点的 \(h_i\)
\(\text{long long}\)

Code

#include<bits/stdc++.h>
#define maxn 200003
using namespace std;
struct node{
	long long lmx,rmx,mx,lr,rr,r;
	node():lmx(0),rmx(0),mx(0),lr(0),rr(0),r(0){}
}t[maxn<<2];
int n,d[maxn],h[maxn],m;
void pushup(node& t1,const node& t2,const node& t3,int mid){
	t1.lmx=max(t2.lmx,t3.lmx+t2.mx+d[mid]);
	t1.rmx=max(t3.rmx,t2.rmx+t3.mx+d[mid]);
	t1.mx=max(max(t2.mx,t3.mx),t2.rmx+t3.lmx+d[mid]);
	t1.lr=max(t2.lr,t3.lr+t2.mx+d[mid]);
	t1.rr=max(t3.rr,t2.rr+t3.mx+d[mid]);
	t1.r=max(max(t2.r,t3.r),t2.rr+t3.lr+d[mid]);
}
void build(int p,int l,int r){
	if(l==r){
		t[p].lmx=t[p].rmx=t[p].mx=0;
		t[p].lr=t[p].rr=t[p].r=2ll*h[l];
		return;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	pushup(t[p],t[p<<1],t[p<<1|1],mid);
}
node query(int p,int l,int r,int seg_l,int seg_r){
	if(seg_l<=l&&r<=seg_r){
		return t[p];
	}
	int mid=(l+r)>>1;
	node tmp1,tmp2,ret;
	if(seg_l<=mid&&seg_r>mid){
		tmp1=query(p<<1,l,mid,seg_l,seg_r);
		tmp2=query(p<<1|1,mid+1,r,seg_l,seg_r);
		pushup(ret,tmp1,tmp2,mid);
	}
	else if(seg_l<=mid)ret=query(p<<1,l,mid,seg_l,seg_r);
	else if(seg_r>mid)ret=query(p<<1|1,mid+1,r,seg_l,seg_r);
	return ret;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",d+i),d[i+n]=d[i];
	for(int i=1;i<=n;i++)scanf("%d",h+i),h[i+n]=h[i];
	build(1,1,n+n);
	while(m--){
		int a,b;
		scanf("%d%d",&a,&b);
		if(a<=b){
			a+=n-1;
			b++;
		}
		else{
			a--;
			b++;
		}
		node tmp=query(1,1,n+n,b,a);
		cout<<tmp.r<<endl;
	}
	return 0;
}
posted @ 2019-03-18 18:05  chc_1234567890  阅读(186)  评论(0编辑  收藏  举报