【Codeforces 55D】Beautiful numbers

题目传送门:http://codeforces.com/contest/55/problem/D
官方题解:http://codeforces.com/blog/entry/1109
中文题面:number_dp_by_zky

之前做数位dp的题目,一直强调数位间的独立性
然而现在看来,不独立也是可以上数位dp的

题解直接看上面给的“中文题面”里的题解吧,zky的题解真的是超级棒(๑•̀ㅂ•́)و✧
我来说一说代码实现的三种方式:

1)像之前的代码一样,先预处理,然后查询的时候在数组上搞一搞
优点:对于多组询问特别好用
缺点:因为是预处理,所以对于有些题目可能很麻烦,甚至不能预处理

2)对于每一次询问单独dp,记录是否达到上限
优点:代码好写(不用于处理,直接写一个dp就成)
缺点:多组询问没法处理

3)对于每一次询问DFS,如果这一位没有受到任何限制就记忆化
这种方法是我在看这位神犇的代码的时候看到的:http://codeforces.com/contest/55/submission/3692033
优点:代码更好写,且对于多组询问相对友好(仔细想一想,他的查询次数应该不会劣于方法1?)
缺点:如果位数特别大(什么1e5,1e6之类的),则效果可能不太好

总的来说,我似乎爱上了第三种写法 = ̄ω ̄=
以后数位dp的题应该是首选第三种吧!

#include<bits/stdc++.h>
#define LL long long
using namespace std;

int MOD[]={1,1,2,3,4,5,6,7,8,9,10,12,14,15,18,20,21,24,28,30,35,36,40,42,45,56,60,63,70,72,84,90,105,120,126,140,168,180,210,252,280,315,360,420,504,630,840,1260,2520};
int pos[2530],lcm[50][50],sta[20]; 
LL f[20][50][2530];

LL GCD(LL a, LL b) {return b?GCD(b,a%b):a;}
LL LCM(LL a, LL b) {return a/GCD(a,b)*b;}


LL DFS(int t, int lm, int mod, bool top) {
	if (t == 0) {
		return !(mod % MOD[lm]);
	} else if (~f[t][lm][mod] && !top) {
		return f[t][lm][mod];	
	} else {
		LL ret = 0;
		for (int i=0,ty=(top>0?sta[t]:9),tmp;i<=ty;i++) {
			tmp = lcm[lm][i];
			ret += DFS(t-1,tmp,(mod*10+i)%2520,top&&i==sta[t]);
		}
		return top?ret:f[t][lm][mod] = ret;
	}
}

inline LL cal(LL lim) {
	int cnt = 0;
	while (lim) {
		sta[++cnt] = lim % 10;
		lim /= 10;
	}
	return DFS(cnt,1,0,1);
}

inline LL read(){
	char c=getchar(); LL ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();}
	return ret*f;
}

int main(){
	memset(f,-1,sizeof(f));
	for (int i=1;i<=48;i++) {
		pos[MOD[i]] = i;
	}
	for (int i=0;i<=48;i++) {
		for (int j=0;j<=48;j++) {
			lcm[i][j] = pos[LCM(MOD[i],MOD[j])];
		}
	} 
	for (int T=read();T;--T) {
		LL l = read(), r = read();
		printf("%I64d\n",cal(r)-cal(l-1));
	}
	return 0;
}

【BZOJ 4518】[Sdoi2016] 征途

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4518
数据生成器:http://paste.ubuntu.com/23249800/

做过玩具装箱的童鞋,看一眼就知道是斜率DP吧?

#include<bits/stdc++.h>
#define pow(x) ((x)*(x))
#define LL long long
using namespace std;

const int N = 3000+9;
const LL INF = 1e16;

LL f[N][N];
short n,m,l[N],sum,que[N][N],t1[N],t2[N];
double slope[N][N],Y[N][N];

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();}
	return ret*f;
}

int main(){ 
	n = read(); m = read();
	for (int i=1;i<=n;i++) sum += (l[i] = read()), l[i] += l[i-1];
	for (int i=0;i<m;i++) t1[i] = 1, f[n][i] = -1; t2[0] = 1;
	for (int i=1;i<=n;i++) for (int j=m-1;~j;j--) {
		if (t1[j]>t2[j]) continue; double tmp = 2.0*m*((double)m*l[i]-sum);
		while (t2[j] > t1[j] && slope[j][t1[j]] <= tmp) t1[j]++; 
		f[i][j+1] = f[que[j][t1[j]]][j] + pow(sum-(LL)m*(l[i]-l[que[j][t1[j]]]));
		tmp = f[i][j+1] + pow((double)m*l[i]); 
		while (t1[j+1] < t2[j+1] && ((tmp-Y[j+1][t2[j+1]])/(l[i]-l[que[j+1][t2[j+1]]]) <= slope[j+1][t2[j+1]-1])) t2[j+1]--;
		if (t1[j+1] <= t2[j+1]) slope[j+1][t2[j+1]] = (tmp-Y[j+1][t2[j+1]])/(l[i]-l[que[j+1][t2[j+1]]]); 
		t2[j+1]++; que[j+1][t2[j+1]] = i; Y[j+1][t2[j+1]] = tmp; 		
	} LL vout = INF;
	for (int i=1;i<=m;i++) if (~f[n][i]) vout = min(vout,f[n][i]+(LL)(m-i)*pow(sum));
	printf("%lld\n",vout/m); return 0;
}

然而再zgs的OJ上莫名其妙RE了两个点?
奥妙重重……..

【UOJ 137】[UER #3] 开学前的日历

题目传送门:http://uoj.ac/problem/137
官方题解:http://vfleaking.blog.uoj.ac/blog/714

这个题,考试的时候想到了50分的算法,但没写出来QAQ
都搞到这个程度了:
45648645
还是没有想出来,可惜啊!

70分算法的关键:\(\left( \begin{array}{l}
x\\
y
\end{array} \right) = \left( \begin{array}{l}
x – 1\\
y
\end{array} \right) + \left( \begin{array}{l}
x – 1\\
y – 1
\end{array} \right)\)

100分的关键:
看一看上面那个图,组合数实际的意义是从(u,v)走到每个点的路径的个数
于是搞一搞dp即可

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N = 300+9;
const int MOD = 998244353;

int f[N][N][N*2],n,m,q,X;

inline int read(){
	X = (100000005*(LL)X+20150823) % MOD;
	return X / 100;
}

int main(){
	cin>>m>>n>>q>>X;
	for (int i=1,u,v,k;i<=q;i++) {
		v = read()%m+1, u = read()%n+1, k = read()%(n+m-v-u+1);
		f[u][v][k]++;
	} 
	for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) {
		for (int k=0;k<=n+m;k++) (f[i][j][k] += (f[i-1][j][k+1] + f[i][j-1][k+1]) % MOD) %= MOD;
		(f[i][j][0] += (f[i-1][j][0] + f[i][j-1][0]) % MOD) %= MOD;
	}
	for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) 
		printf("%d%c",f[i][j][0],(i==n?'\n':' '));
	return 0;
}

【Codeforces 713C】Sonya and Problem Wihtout a Legend

题目传送门:http://codeforces.com/contest/713/problem/C

我™之前做过这原题!然而考试的时候没想到怎么做QAQ
V5[YANBJ`4%A2`%PIH$BH_F
I well vegatable are!

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N = 3000+9;
const LL INF = 1e15;

int arr[N],hash[N],n,tot;
LL f[N][N],MN[N]; 

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();}
	return ret*f;
}

#define update(x,y) (x=((x)==-1||(y)<(x)?(y):(x)))
#define abs(x) ((x)>0?(x):-(x))

int main(){
	n = read(); 
	for (int i=1;i<=n;i++) hash[i] = arr[i] = read() - i;
	sort(hash+1,hash+1+n); tot = unique(hash+1,hash+1+n) - hash - 1;
	for (int i=1;i<=n;i++) memset(f[i],-1,sizeof(f[i])), MN[i] = -1;
	for (int i=1;i<=n;i++) {
		LL best = INF;
		for (int j=1;j<=tot;j++) {
			if (~f[i-1][j]) best = min(best, f[i-1][j]);
			update(f[i][j],best+abs(arr[i]-hash[j]));
		}
	} 
	LL vout = INF;
	for (int i=1;i<=tot;i++) if (~f[n][i])
		vout = min(vout, f[n][i]);
	cout<<vout; 
	return 0;
}

至于为什么减去下标答案不会变?
我们可以考虑差分序列啦!

—– UPD 2016.9.14 —–
这题看策爷的代码,可以用左偏树搞到O(nlogn)

原来这个题目可以贪心!
考虑最后的样子,一定长这样:
556487545
加入一个堆,其中位数不满足整体不减的话,即与左边的堆合并
为什么这么贪心的是对的呢?因为不管你砍哪一步分开,那一部分的差距都会更大,即不可能成为最优解

【BZOJ 4626】[BeiJing2016] 空袭

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4626
数据生成器:http://paste.ubuntu.com/23171656/

这题,是我到目前为止做过的最恶心的题目
没有之一

如果击中,那么三级狗一定在连续$a_i$个回合里没有转向,并且有一个回合没有动
那么$DP$的时候记录一下最近$a_i$次的移动情况即可
chenyushuo提供的资料:http://pan.baidu.com/s/1kVg3uvl

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int MOD = 1000000007;

int X,Y,OP,n,m,T,vis[30][30],hit[60][13][13],f[2][22][22][5][21][13],W=1,P;
int dx[]={0,1,0,-1,0},dy[]={0,0,1,0,-1},vout[22][22],del[60];
char pat[30];

int main(){
	cin>>n>>m>>T; 
	for (int i=1;i<=n;i++) {
		scanf("%s",pat+1);
		for (int j=1;j<=m;j++) 
			if (isdigit(pat[j])) vis[i][j] = 1, f[P][i][j][pat[j]-'0'+1][0][0] = 1;
			else if (pat[j] == '.') vis[i][j] = 1;
	} 
	for (int i=1;i<T;i++) cin>>del[i];
	for (int k=0;k<=T;k++) for (int go=0;go<=12;go++) for (int dly=0;dly<=go;dly++)
		for (int w=dly;w<go;w++) if (k-w >= 1 && del[k-w] == w+1) hit[k][go][dly] = 1;
	for (int k=1;k<=T;k++,W^=1,P^=1,memset(f[W],0,sizeof(f[W]))) for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) 
		if (vis[i][j]) for (int to=1;to<=4;to++) for (int go=0;go<=12;go++) for (int dl=0,tmp;dl<=12;dl++) {
			if (!(tmp=f[P][i][j][to][go][dl])) continue;
			if (!hit[k-1][dl][0]) (f[W][i][j][to][min(12,dl+1)][0] += tmp) %= MOD;
			if (vis[i+dx[to]][j+dy[to]] && !hit[k-1][go][dl]) 
				(f[W][i+dx[to]][j+dy[to]][to][min(12,go+1)][min(12,dl+1)] += tmp) %= MOD;
			for (int op=1;op<=4;op++) if (op != to && vis[i+dx[op]][j+dy[op]]) 
				(f[W][i+dx[op]][j+dy[op]][op][0][0] += tmp) %= MOD;
	}
	for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) for (int to=1;to<=4;to++) 
		for (int go=0;go<=12;go++) for (int dl=0;dl<=12;dl++) 
			(vout[i][j] += f[P][i][j][to][go][dl]) %= MOD;
	for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) 
		printf("%d%c",vout[i][j],j==m?'\n':' ');
	return 0;
}

【BZOJ 3962】[WF2011] Coffee Central

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3962

这个玩意,貌似可以暴力?
预处理出斜着的线上的点有多少,这样在暴力转移的时候,可以做到O(1)
然后就是写代码的事情了,然而写了两个小时了,没写出来QAQ
弃疗………..

—– 2016.9.6 更新 —–
耐着性子码完了代码
为什么觉得线段求交点常数大?
为什么要作死直接分类讨论 (╯‵□′)╯︵┻━┻

#include<bits/stdc++.h>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int N = 1000+9;

int n,m,q,sz,head[N],vout,X,Y;
int mat[N][N],f[2][N][N];

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

inline void prework(){
	for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) f[0][i][j] = f[0][i-1][j-1] + mat[i][j];
	for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) f[1][i][j] = f[1][i+1][j-1] + mat[i][j]; 
}
 
inline int pro(int x1, int y1, int x2, int y2, int t) {
	int ret = 0;
	if (!t) {
		x2--; y2--;
		if (x1 < 1 || y1 < 1) ret += 0;
		else if (x1 <= n && y1 <= m) ret += f[t][x1][y1];
		else if (x1 > n) ret += (y1-(x1-n)<=m && y1-(x1-n)>=1)? f[t][n][y1-(x1-n)]: 0;
		else ret += (1<=x1-(y1-m) && x1-(y1-m)<=n)? f[t][x1-(y1-m)][m]: 0; 
		
		if (x2 < 1 || y2 < 1) ret -= 0;
		else if (x2 <= n && y2 <= m) ret -= f[t][x2][y2];
		else if (x2 > n) ret -= (y2-(x2-n)<=m && y2-(x2-n)>=1)? f[t][n][y2-(x2-n)]: 0;
		else ret -= (1<=x2-(y2-m) && x2-(y2-m)<=n)? f[t][m][2-(y2-m)]: 0;
	} else {
		x2++; y2--;
		if (x1 > n || y1 < 1) ret += 0;
		else if (x1 >= 1 && y1 <= m) ret += f[t][x1][y1];
		else if (x1 < 1) ret += (y1-(1-x1)>=1 && y1-(1-x1)<=m)? f[t][1][y1-(1-x1)]: 0;
		else ret += (x1+(y1-m)>=1 && x1+(y1-m)<=n)? f[t][x1 + (y1 - m)][m]: 0;
		
		if (x2 > n || y2 < 1) ret -= 0;
		else if (x2 >= 1 && y2 <= m) ret -= f[t][x2][y2];
		else if (x2 < 1) ret -= (y2-(1-x2)>=1 && y2-(1-x2)<=m)? f[t][1][y2 -(1-x2)]: 0; 
		else ret -= (1<=x2+(y2-m) && x2+(y2-m)<=n)? f[t][x2+(y2-m)][m]: 0;
	} return ret;
} 

inline void solve(int lim){
	vout = 0; X = 1; Y = 1;
	for (int j=1;j<=m;j++) for (int i=1;i<=n;i++)
		if (i + j > lim + 2) break;
		else vout += mat[i][j];
	head[1] = vout; int tmp = vout;
	
	for (int j=1;j<=m;j++) {
		for (int i=1;i<n;i++) { 
			tmp += pro(i+lim+1,j,i+1,j-lim,0); // ¨J 
			tmp -= pro(i,j+lim,i-lim,j,0);     // ¨L 
			tmp += pro(i+1,j+lim,i+lim+1,j,1); // ¨K 
			tmp -= pro(i-lim,j,i,j-lim,1);     // ¨I 
			if (i + lim + 1 <= n) tmp -= mat[i+lim+1][j];
			if (i - lim >= 1) tmp += mat[i-lim][j];
			if (tmp > vout) vout = tmp, X = i+1, Y = j;
		}
		if (j < m) {
			tmp = head[j];
			tmp += pro(1,j+lim+1,1+lim,j+1,1);//¨K 
			tmp += pro(1,j+lim+1,1-lim,j+1,0);//¨L 
			tmp -= pro(1+lim,j,1,j-lim,0);//¨J 
			tmp -= pro(1-lim,j,1,j-lim,1);//¨I 
			if (j + lim + 1 <= m) tmp -= mat[1][j+lim+1];
			if (j - lim  >= 1) tmp += mat[1][j-lim];
			if (tmp > vout) vout = tmp, X = 1, Y = j+1;
			head[j+1] = tmp;
		}
	}	 
	
}

inline void init(int w){
	memset(f,0,sizeof(f));
	memset(mat,0,sizeof(mat));
	printf("Case %d:\n",w);
}

int main(){
	for (int T=1;scanf("%d%d",&n,&m) && n && m;T++) { 
		init(T); sz = read(); q = read();  
		for (int i=1,x,y;i<=sz;i++) x = read(), y = read(), mat[x][y]++;
		prework(); 
		for (int k=1;k<=q;k++) {
			solve(min(m+n,read()));
			printf("%d (%d,%d)\n",vout,X,Y);
		} 
	}
	return 0;
}

然而DZY告诉我们,这货可以变成正方形?
参见:http://dzy493941464.is-programmer.com/posts/86498.html
仔细想了一想:我们可以通过将整个图旋转45°,然后重新编号,然后就变成了正方形?
然后就是很常规的滑动窗口了?

—– UPD 2016.6.9 —–
坐标旋转的代码

#include<bits/stdc++.h>
using namespace std;

const int N = 2000+9;
int n,k,q,mat[N][N],sta[N],sum[N][N],MX;

inline int read(){
	char c=getchar(); int ret=0,f=1; 
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();} 
	return ret*f;
}

#define SUM(x,y) sum[max(0,min(x,MX))][max(0,min(y,MX))]
inline void solve(int lim) { int vout = 0;
	for (int j=1;j<=n;j++) for (int i=1,x,y;i<=n;i++) x = sta[i]-j+1, y = i+j-1,
		vout = max(vout, SUM(x+lim,y+lim) + SUM(x-lim-1,y-lim-1) - SUM(x+lim,y-lim-1) - SUM(x-lim-1,y+lim));
	printf("%d\n",vout);
}

int main(){
	n = read(); k = read(); q = read(); MX = n * 2 - 1; 
	sta[1] = n; for (int i=2;i<=n;i++) sta[i] = sta[i-1] + 1;
	for (int i=n+1;i<=n*2-1;i++) sta[i] = sta[i-1] - 1;
	for (int i=k,x,y;i;--i) x = read(), y = read(), mat[sta[x]-y+1][x+y-1] = 1;
	for (int j=1;j<=MX;j++) for (int i=1;i<=MX;i++) sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + mat[i][j];
	for (int i=1;i<=q;i++) solve(read());
	return 0;
} 

【BZOJ 4521】[Cqoi2016] 手机号码

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4521
数据生成器:http://paste.ubuntu.com/23135878/
官方数据:http://pan.baidu.com/s/1hsqc4Va

这个题,瞄一眼就知道是数位DP
然而转移比较恶心,在考场上代码就写了两个小时
然而最后因为一个局部变量没有清零,结果wa得只剩一个点
为什么本机对拍不wa (╯‵□′)╯︵┻━┻

#include<bits/stdc++.h>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

LL f[12][10][5][5],l,r;

inline LL read(){
	char c=getchar(); LL ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

inline void prework(){
	for (int i=0;i<=9;i++) if (i != 4 && i != 8) f[1][i][1][0] = 1;
	f[1][4][1][1] = f[1][8][1][2] = 1;
	for (int i=2;i<=11;i++) for (int j=0;j<=9;j++) {
		if (j == 4) {
			for (int p=0;p<=9;p++) if (p != j) for (int k=1;k<=2;k++) for (int ty=0;ty<=1;ty++) 
				f[i][j][1][1] += f[i-1][p][k][ty];
			f[i][j][2][1] = f[i-1][4][1][1];
			f[i][j][3][1] = f[i-1][4][2][1];
			for (int p=0;p<=9;p++) for (int ty=0;ty<=1;ty++)
				f[i][j][3][1] += f[i-1][p][3][ty];
		} else if (j == 8) {
			for (int p=0;p<=9;p++) if (p != j) for (int k=1;k<=2;k++) f[i][j][1][2] += f[i-1][p][k][0] + f[i-1][p][k][2]; 
			f[i][j][2][2] = f[i-1][8][1][2];
			f[i][j][3][2] = f[i-1][8][2][2];
			for (int p=0;p<=9;p++) f[i][j][3][2] += f[i-1][p][3][0] + f[i-1][p][3][2];
		} else for (int t=0;t<=2;t++) {
			for (int p=0;p<=9;p++) if (p != j) for (int k=1;k<=2;k++) f[i][j][1][t] += f[i-1][p][k][t];
			f[i][j][2][t] = f[i-1][j][1][t];
			f[i][j][3][t] = f[i-1][j][2][t];
			for (int p=0;p<=9;p++) f[i][j][3][t] += f[i-1][p][3][t];
		}
	}
}

inline bool judge(LL w) {
	static int dig[15]; bool t1=0,t4=0,t8=0;
	for (int i=1;i<=11;i++) dig[i] = w % 10, w /= 10;
	for (int i=1;i<=11;i++) if (dig[i] == 4) t4 = 1;
	for (int i=1;i<=11;i++) if (dig[i] == 8) t8 = 1;
	for (int i=3;i<=11;i++) if (dig[i] == dig[i-1] && dig[i-1] == dig[i-2]) t1 = 1;
	return t1 && !(t4 && t8);
}

inline LL cal(LL lim) {
	LL ret = 0; bool t4=0, t8=0, CNT=0; static int dig[15];
	for (int i=1;i<=11;i++) dig[i] = lim % 10, lim /= 10;
	
	for (int i=1;i<dig[11];i++) for (int ty=0;ty<=2;ty++) ret += f[11][i][3][ty];
	for (int k=10;k;k--) {
		if (dig[k+1] == 4) t4 = 1; if (dig[k+1] == 8) t8 = 1;
		if (t4 && t8) break;
		
		int cnt = 1; for (int w=k+2;w<=11;w++) if (dig[w] != dig[k+1]) break; else cnt++;
		if (cnt >= 3) CNT = 1;
		
		for (int j=0,tmp=(k!=1);j<=dig[k]-tmp;j++) 
			if (CNT) for (int t=1;t<=3;t++) {
				ret += f[k][j][t][0];
				if (!t4) ret += f[k][j][t][2];
				if (!t8) ret += f[k][j][t][1];
			} else {
				if (dig[k+1] == j) {
					int stp = max(1,3-cnt);
					for (int t=stp;t<=3;t++) {
						ret += f[k][j][t][0];
						if (!t4) ret += f[k][j][t][2];
						if (!t8) ret += f[k][j][t][1];
					}
				} else {
					ret += f[k][j][3][0];
					if (!t4) ret += f[k][j][3][2];
					if (!t8) ret += f[k][j][3][1];
				}
			}
	} 
	return ret;
}

int main(){
	prework();
	l = read(); r = read();
    cout<<cal(r)-cal(l)+judge(l);
	return 0;
}

【Codeforces 710E】Generate a String

题目传送门:http://codeforces.com/contest/710/problem/E
官方题解:http://codeforces.com/blog/entry/46761

这题,做法很多:
有简单粗暴型:http://www.cnblogs.com/Coolxxx/p/5797798.html
也有优雅递推型:http://blog.csdn.net/qq_33184171/article/details/52289905
我是第二种,不过第二种有一个东西需要证明:至少存在一组最优解使得-1操作至多连续进行1次

#include<bits/stdc++.h>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int N = 1e7+9; 

int n,x,y;
LL f[N];

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

int main(){
	n = read(); x = read(); y = read();
	f[1] = x; for (int i=2;i<=n;i++) {
		f[i] = f[i-1] + x;
		if (i & 1) f[i] = min(f[i], f[i+1>>1] + x + y);
		else f[i] = min(f[i], f[i>>1] + y);
	}
	printf("%I64d\n",f[n]);
	return 0;
}

【Codeforces 711C】Coloring Trees

题目传送门:http://codeforces.com/contest/711/problem/C
数据生成器:http://paste.ubuntu.com/23124114/
官方数据:http://codeforces.com/blog/entry/46830

O(n^4)的DP还是很好想,但这货的细节比较多,我调了3个小时FS~3Z]@~(4B0{S~)AKZ2G88
然后是可以优化到O(n^3),因为只有相不相等才影响答案,所以只用记录最小的两种颜色即可
嘴巴上AC还是很容易的,但代码写起来更恶心,所以弃疗QRRXCIEEY4QTA4`}]CL@RVL

#include<bits/stdc++.h>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int N = 100+9;
const int INF = 1000000000+9;

int q[N][N],n,m,K,arr[N],cur,w,p;
LL f[2][N][N];

inline int read(){
	char c=getchar(); int ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

inline void update(LL &w, LL sta) {
	if (!w || sta < w) w = sta;
}

int main(){
	n = read(); m = read(); K = read();
	for (int i=1;i<=n;i++) {
		arr[i] = read();
		if (!arr[i-1]) cur += (arr[i] > 0);
		else cur += (arr[i] != arr[i-1] && arr[i] != arr[i+1]);
	} 
	for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) q[i][j] = read();
	if (!arr[1]) for (int j=1;j<=m;j++) { 
		if (j != arr[2]) f[p][j][cur+1] = q[1][j]+1; 
		else f[p][j][cur] = q[1][j]+1;
	} else f[p][arr[1]][cur] = 1; w = 1;
	for (int i=2;i<=n;i++,w^=1,p^=1) {
		memset(f[w],0,sizeof(f[w]));
		if (arr[i]) for (int j=1;j<=m;j++) for (int k=1;k<=n;k++) 
			{if (f[p][j][k]) update(f[w][arr[i]][k],f[p][j][k]);}
		else for (int j=1;j<=m;j++) {
			for (int k=1;k<=n;k++) for (int t=1;t<=m;t++) if (f[p][t][k])
				if (j != t) update(f[w][j][k+(j != arr[i+1])],f[p][t][k] + q[i][j]);
				else update(f[w][j][k-(j == arr[i+1])],f[p][t][k] + q[i][j]);
		}
	} 
	LL vout = 0; 
	for (int i=1;i<=m;i++) if (f[p][i][K])
		update(vout, f[p][i][K]);
	if (!vout && cur != K) cout<<-1;
	else cout<<vout-1;
	return 0;
}

【Codeforces 703E】Mishka and Divisors

题目传送门:http://codeforces.com/contest/703/problem/E
官方题解:http://codeforces.com/blog/entry/46434
中文题面:http://www.cnblogs.com/dramstadt/p/5759206.html

题解的话,看官方题解就好
唯一想吐槽的就是:CF上居然卡常!HP@{Q%Y1HMU{H9M4V]{N6)D
看看这通过的名单,™大家都是压线过的啊
456785132465

#include<bits/stdc++.h>
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int M = 7000;
const int N = 1000+9;
const int INF = 10000000;

LL k,Hash[M],buf[M],sum[2][M];
int n,cnt,f[2][M],nxt[N][M],vout[N][M];
unordered_map<LL,int> idx;

inline LL read(){
	char c=getchar(); LL ret=0,f=1;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret*f;
}

inline LL find(LL w){
	int l=1, r=cnt, mid;
	while (l <= r) {
		mid = l + r >> 1;
		if (Hash[mid] == w) return mid;
		else if (Hash[mid] < w) l = mid+1;
		else r = mid-1;
	} 
}

inline void Decomposision(LL num) {
	LL lim = sqrt(num); if (lim*lim != num) lim++;
	for (int i=1;i<=lim;i++) if (num % i == 0) buf[++cnt] = i, buf[++cnt] = num/i;
	if (lim*lim == num) cnt--;
	for (int i=1;i<=cnt;i++) Hash[i] = buf[i];
	sort(Hash+1,Hash+1+cnt);
	for (int i=1;i<=cnt;i++) idx[buf[i]] = find(buf[i]);
}

inline LL GCD(LL a, LL b){
	while (b) {
		a = a%b;
		swap(a, b);
	}
	return a;
}

inline void SPJ(){
	if (k == 1) {
		LL vout = 1, tmp = read();
		for (int i=2;i<=n;i++) {
			LL t1 = read(); if (t1 < tmp) 
			tmp = t1, vout = i;
		} cout<<1<<endl<<vout; exit(0);
	}
}

int main(){
	n = read(); k = read(); SPJ();
	Decomposision(k); 
	for (int i=2;i<=cnt;i++) f[0][i] = INF; int now=1,pre=0;
	for (int i=1;i<=n;i++,pre^=1,now^=1) {
		LL w = read(), t2, t3 = GCD(w,k);
		for (int j=2,tmp,t1;j<=cnt;j++) {
			tmp = f[pre][t1=idx[Hash[j]/GCD(Hash[j],t3)]]+1;
			t2 = w + sum[pre][t1];
			if (f[pre][j] > tmp  || (f[pre][j] == tmp && t2 <= sum[pre][j])) 
				f[now][j] = tmp, nxt[i][j] = t1, vout[i][j] = i, sum[now][j] = t2;
			else f[now][j] = f[pre][j], nxt[i][j] = j, vout[i][j] = 0, sum[now][j] = sum[pre][j];
		}
	}
	if (f[pre][cnt] == INF) printf("-1\n");
	else {
		printf("%d\n",f[pre][cnt]);
		LL w = cnt, stp = n;
		while (w) {
			if (vout[stp][w]) printf("%d ",vout[stp][w]);
			w = nxt[stp][w]; stp--;
		}
	}
	return 0;
}

【BZOJ 2595】[Wc2008] 游览计划

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2595
数据生成器:http://paste.ubuntu.com/23070779/

斯坦纳树第一题! 撒花~ *★,°*:.☆( ̄▽ ̄)/$:*.°★* 。
然而感觉斯坦纳树,撑死了算一类DP问题,为什么要叫算法呢QAQ
其实斯坦纳树,说白了就是一个状压DP?

题解的话,让我们召唤神犇:http://www.cnblogs.com/lidaxin/p/5299762.html

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define id(x,y) (((y)-1)*n+(x))
using namespace std;

const int MAXN = 19*19;
const int N = 2500;
const int INF = 0x3f3f3f3f;

int n,m,cnt,mat[MAXN],f[MAXN][N],num[MAXN],X,Y,vis[MAXN][N],pv,avl[MAXN];
queue<pair<int,int> > que;
pair<int,int> from[MAXN][N];

inline int read(){
	char c=getchar(); int ret=0;
	while (c<'0'||c>'9') c=getchar();
	while (c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
	return ret;
}

inline void rev(int w){
	Y = w / n + 1;
	X = w - (Y-1)*n;
	if (!X) X = n, Y--;
}

inline void update(int op, int nv, int pos, int w){
	if (f[pos][w] > nv) {
		f[pos][w] = nv;
		from[pos][w] = make_pair(op,w);
		if (!vis[pos][w]) vis[pos][w] = 1, que.push(make_pair(pos,w));
	}
}

inline void SPFA(){
	while (!que.empty()) {
		rev(que.front().first);
		int x=X, y=Y, w=que.front().second, pos=que.front().first; 
		vis[pos][w] = 0; que.pop();
		if (x > 1) update(pos,f[pos][w]+mat[id(x-1,y)],id(x-1,y),w);
		if (y > 1) update(pos,f[pos][w]+mat[id(x,y-1)],id(x,y-1),w);
		if (x < n) update(pos,f[pos][w]+mat[id(x+1,y)],id(x+1,y),w);
		if (y < m) update(pos,f[pos][w]+mat[id(x,y+1)],id(x,y+1),w);
	}
}

inline void Steiner_Tree(){
	for (int w=1,lim=1<<cnt;w<lim;w++) {
		for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) {
			for (int k=w&(w-1);k;k=w&(k-1)) {
				int tmp = f[id(i,j)][k] + f[id(i,j)][w^k] - mat[id(i,j)];
				if (f[id(i,j)][w] > tmp) f[id(i,j)][w] = tmp, from[id(i,j)][w] = make_pair(id(i,j),k);		
			}
			if (f[id(i,j)][w] != INF) que.push(make_pair(id(i,j),w)), vis[id(i,j)][w] = 1;
		} SPFA();
	}
}

void Mark_Ans(pair<int,int> tmp){
	int pos=tmp.first, w = tmp.second; if (!pos) return; 
	rev(pos); int x = X, y = Y; avl[id(x,y)] = 1; 
	Mark_Ans(from[pos][w]); 
	if (from[pos][w].first == pos) Mark_Ans(make_pair(id(x,y),w-from[pos][w].second));
	
}

int main(){
	m = read(); n = read();
	for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) {
		memset(f[id(i,j)],0x3f,sizeof(f[id(i,j)]));
		f[id(i,j)][0] = 0; mat[id(i,j)] = read(); 
		if (!mat[id(i,j)]) f[id(i,j)][1<<cnt++] = 0, pv = id(i,j);
	} 
	Steiner_Tree(); Mark_Ans(make_pair(pv,(1<<cnt)-1));
	printf("%d\n",f[pv][(1<<cnt)-1]);
	for (int j=1;j<=m;j++) {
		for (int i=1;i<=n;i++) 
			if (!mat[id(i,j)]) putchar('x');
			else if (avl[id(i,j)]) putchar('o');
			else putchar('_');
		putchar('\n');
	}
	return 0;
}

【COGS 1478】麻球繁衍

题目传送门:http://cogs.top/cogs/problem/problem.php?pid=1487

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

const int MAXN = 1000+9;

int n,m;
double w,p[MAXN],vout;

inline int read(){
	char c=getchar(); int buf=0,f=1;
	while (c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0'){buf=buf*10+c-'0';c=getchar();}
	return buf*f;
}

int main(){
	freopen("tribbles.in","r",stdin);
	freopen("tribbles.out","w",stdout);
	for (int T=1,TT=read();T<=TT;T++){
		n = read(), w = read(); m = read(); 
		for (int i=0;i<n;i++) scanf("%lf",&p[i]);
		vout = p[0];
		for (int k=2;k<=m;k++) {
			double tmp = 0;
			for (int i=0;i<n;i++) tmp += p[i]*pow(vout,i);
			vout = tmp; 
		}
		printf("Case #%d: %.7lf\n",T,pow(vout, w));
	} 
	return 0;
} 

【BZOJ 1414】[ZJOI2009] 对称的正方形

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1414

题号“1414”,还真的是把我做得“要死要死的”!做了一整天QAQ
Hash version:

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
 
const int MX = 0;
const int MAXN = 2000+9;
unsigned int SEEDX = 37;
unsigned int SEEDY = 137;
 
int n,m; LL vout;
unsigned int px[2000+9],py[2000+9],mat[MAXN][MAXN],f[5][MAXN][MAXN];
 
inline int read(){
    char c=getchar(); int ret=0;
    while (c<'0'||c>'9') c=getchar();
    while (c<='9'&&c>='0'){ret=ret*10+c-'0';c=getchar();}
    return ret;
}
 
inline void init(){
    m = read(); n = read(); vout = (unsigned int)n*m;
    for (int j=1;j<=m;j++) {
        for (int i=1;i<=n*2+1;i++) mat[i][j*2-1] = MX;
        for (int i=1;i<=n;i++) mat[i*2][j*2] = read(), mat[i*2-1][j*2] = MX;
        mat[n*2+1][j*2] = MX;
    } for (int i=1;i<=n*2+1;i++) mat[i][m*2+1] = MX;
    n = n*2+1; m = m*2+1;
}
 
inline void Hash_init(){
    px[0] = 1; for (int i=1;i<=2001;i++) px[i] = SEEDX*px[i-1];
    py[0] = 1; for (int i=1;i<=2001;i++) py[i] = SEEDY*py[i-1];
    for (int i=n,g=1;i;i--,g++) for (int j=1,h=1;j<=m;j++,h++) f[1][i][j] = px[g]*py[h]*mat[i][j] + f[1][i+1][j] + f[1][i][j-1] - f[1][i+1][j-1];
    for (int i=1,g=1;i<=n;i++,g++) for (int j=1,h=1;j<=m;j++,h++) f[2][i][j] = px[g]*py[h]*mat[i][j] + f[2][i-1][j] + f[2][i][j-1] - f[2][i-1][j-1];
    for (int i=1,g=1;i<=n;i++,g++) for (int j=m,h=1;j;j--,h++) f[3][i][j] = px[g]*py[h]*mat[i][j] + f[3][i-1][j] + f[3][i][j+1] - f[3][i-1][j+1];
    for (int i=n,g=1;i;i--,g++) for (int j=m,h=1;j;j--,h++) f[4][i][j] = px[g]*py[h]*mat[i][j] + f[4][i+1][j] + f[4][i][j+1] - f[4][i+1][j+1];
}
 
inline unsigned int Get_Hash(int t, int x1, int y1, int x2, int y2){
    if (t == 1) return (f[1][x1][y1] + f[1][x2+1][y2-1] - f[1][x2+1][y1] - f[1][x1][y2-1]) * px[2001-(n-x1+1)] * py[2001-y1];
    else if (t == 2) return (f[2][x1][y1] + f[2][x2-1][y2-1] - f[2][x2-1][y1] - f[2][x1][y2-1])* px[2001-x1] * py[2001-y1];
    else if (t == 3) return (f[3][x1][y1] + f[3][x2-1][y2+1] - f[3][x2-1][y1] - f[3][x1][y2+1]) * px[2001-x1] * py[2001-(m-y1+1)];
    else return (f[4][x1][y1] + f[4][x2+1][y2+1] - f[4][x2+1][y1] - f[4][x1][y2+1]) * px[2001-(n-x1+1)] * py[2001-(m-y1+1)];
}
 
inline bool judge(int x, int y, int len){
    unsigned int t1 = Get_Hash(1,x,y,x+len,y-len),t2 = Get_Hash(2,x,y,x-len,y-len);
    if (t1 != t2) return false;
    t1 = Get_Hash(3,x,y,x-len,y+len);
    if (t1 != t2) return false;
    t2 = Get_Hash(4,x,y,x+len,y+len);
    if (t1 != t2) return false;
    else return true;
}
 
inline void solve(){
    for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) if ((i&1) + (j&1) != 1) {
        int l=2,r=min(min(i-1,j-1),min(n-i,m-j)),ans=0,mid;
        while (l <= r) {
            mid = l + r >> 1;
            if (judge(i,j,mid)) l = mid+1, ans = mid;
            else r = mid-1;
        }vout += ans/2;
    }
}
 
int main(){
    init(); Hash_init(); solve();
    printf("%lld\n",vout);
    return 0;
}  

Manacher version:

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
 
const int MAXN = 2000+9;
 
int mat[MAXN][MAXN],n,m,tmp[MAXN],ans[MAXN],que[MAXN],tot,pos[MAXN];
int res_x[MAXN][MAXN],res_y[MAXN][MAXN],sa_y[MAXN][MAXN],sa_x[MAXN][MAXN];
 
inline int read(){
    char c=getchar(); int ret=0;
    while (c<'0'||c>'9') c=getchar();
    while (c<='9'&&c>='0'){ret=ret*10+c-'0';c=getchar();}
    return ret;
}
 
inline void manacher(int lim){
    int MX=0; ans[0] = 0;
    for (int i=1;i<=lim;i++) {
        if (MX+ans[MX] > i) ans[i] = min(MX+ans[MX]-i, ans[MX*2-i]);
        else ans[i] = 0;
        while (tmp[i+ans[i]+1] == tmp[i-ans[i]-1]) ans[i]++;
        if (ans[i]+i > MX+ans[MX]) MX = i;
    }
}
 
inline void DP(int lim){
    tot = 0; pos[0] = 0; int sta = 0;
    for (int i=1;i<=lim;i++) {
        while (tot && ans[i] <= que[tot]) tot--; sta = min(sta, tot);
        que[++tot] = ans[i]; pos[tot] = i; int w = sta;
        while (w < tot && min(que[w],(i-pos[w-1])*2-1) <= min(que[w+1],(i-pos[w])*2-1)) w++;
        sta = w; tmp[i] = min(que[w],(i-pos[w-1])*2-1);
    } 
}

int main(){
    m = read(); n = read();
    for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) mat[i*2][j*2] = read();
    n = n * 2 + 1; m = m * 2 + 1;
     
    for (int i=1;i<=n;i++) {
        for (int j=1;j<=m;j++) tmp[j] = mat[i][j]; tmp[0] = -1; tmp[m+1] = -2;
        manacher(m); 
        for (int j=1;j<=m;j++) sa_y[i][j] = ans[j];
    }
    for (int j=1;j<=m;j++) {
        for (int i=1;i<=n;i++) ans[i] = sa_y[i][j]*2+1;
        DP(n);
        for (int i=1;i<=n;i++) res_x[i][j] = tmp[i];
        for (int i=1;i*2<=n;i++) swap(ans[i],ans[n-i+1]);
        DP(n);
        for (int i=1;i<=n;i++) res_x[i][j] = min(res_x[i][j],tmp[n-i+1]);
    } 
         
    for (int j=1;j<=m;j++) {
        for (int i=1;i<=n;i++) tmp[i] = mat[i][j]; tmp[0] = -1; tmp[n+1] = -2;
        manacher(n); 
        for (int i=1;i<=n;i++) sa_x[i][j] = ans[i];
    }
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++) ans[j] = sa_x[i][j]*2+1;
        DP(m);
        for (int j=1;j<=m;j++) res_y[i][j] = tmp[j];
        for (int j=1;j*2<=m;j++) swap(ans[j],ans[m-j+1]);
        DP(m);
        for (int j=1;j<=m;j++) res_y[i][j] = min(res_y[i][j], tmp[m-j+1]);
    } 
     
    LL vout = (n/2)*(m/2);
    for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) if ((i+j) % 2 == 0)
        vout += max(0,(min(res_x[i][j]-1,res_y[i][j]-1)/2)/2);
    printf("%lld\n",vout);
    return 0;
} 

【BZOJ 1505】[NOI2004] 小H的小屋

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1505

仍然是决策单调性QAQ

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int MAXN = 100+9;
const int MX = 100;

double f[2][MAXN][MAXN],k1,k2;
int n,m,sz[MAXN],sta=1;

#define cal_up(l,r) (k1*((r)-(l))*((r)-(l)))

inline double cal_down(int l, int r, int t){
	int len = r-l, tmp = 0; double ret = 0;
	for (int i=1;i<=t;i++) sz[i] = len/t, tmp += sz[i];
	while (tmp < len) for (int i=1;i<=t && tmp < len;i++) sz[i]++, tmp++;
	for (int i=1;i<=t;i++) ret += k2*sz[i]*sz[i];
	return ret; 
}

inline void Dynamic_Programing(int w, int t){
	for (int i=1;i<=MX;i++) memset(f[w][i],0,sizeof(f[w][i]));
	for (int j=1,t1=1,t2=1;j<=n;j++,t1=1,t2=1) for (int i=1;i<=MX;i++) if (j <= i) {
		for (int h=max(1,t1-3);h<i;h++) for (int g=max(t2-3,1);g<j;g++) if (f[t][h][g]) {			
			double tmp = f[t][h][g] + cal_up(h,i) + cal_down(h,i,j-g);
			if (!f[w][i][j] || f[w][i][j] > tmp) f[w][i][j] = tmp, t1=h, t2=g;
		}
	}
}

int main(){
	scanf("%lf%lf%d%d",&k1,&k2,&m,&n);
	for (int i=1;i<=MX;i++) for (int j=1,lim=min(n,i);j<=lim;j++)
		f[1][i][j] = cal_up(0,i) + cal_down(0,i,j);
	for (int k=2;k<=m;k++,sta^=1) Dynamic_Programing(sta^1,sta);
	printf("%.1lf\n",f[sta][MX][n]);
	return 0;
} 

【BZOJ 2216】[Poi2011] Lightning Conductor

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2216

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int MAXN = 500000+9;
const double EPS = 1e-8;

int arr[MAXN],n,f[MAXN],l[MAXN],r[MAXN],que[MAXN],head,tail;

inline int read(){
	char c=getchar(); int ret=0;
	while (c<'0'||c>'9') c=getchar();
	while (c<='9'&&c>='0'){ret=ret*10+c-'0';c=getchar();}
	return ret;
}

inline double cal(int a, int b){
	return sqrt(abs(a-b)) + arr[a];
}

int main(){
	n = read();
	for (int i=1;i<=n;i++) arr[i] = read();
	
	l[tail=head=1] = 1; r[1] = n; que[1]=1;
	for (int i=2;i<=n;i++) {
		l[tail]++;
		while (tail <= head && r[tail] < l[tail]) tail++;
		f[i] = max(f[i], int(ceil(cal(que[tail],i))+EPS));
		if (cal(i,r[head]) < cal(que[head],r[head])) continue;
		else {
			while (tail <= head && cal(i,l[head]) > cal(que[head],l[head])) head--; 
			if (tail <= head) {
				int ls=l[head],rs=r[head],mid,ans=r[head]-1;
				while (ls <= rs) {
					mid = ls + rs >> 1;
					if (cal(i,mid) < cal(que[head],mid)) ls = mid+1;
					else ans = mid, rs = mid-1;
				}
				r[head] = ans; l[++head] = ans+1; r[head] = n; que[head] = i;
			} else que[++head] = i, l[head] = i, r[head] = n;
		}
	}
	
	l[tail=head=1] = n; r[1] = 1; que[1]=n; que[0]=1;
	for (int i=n-1;i;i--) {
		l[tail]--;
		while (tail <= head && r[tail] > l[tail]) tail++;
		f[i] = max(f[i], int(ceil(cal(que[tail],i))+EPS));
		if (cal(i,r[head]) < cal(que[head],r[head])) continue;
		else {
			while (tail <= head && cal(i,l[head]) > cal(que[head],l[head])) head--; 
			if (tail <= head) {
				int ls=l[head],rs=r[head],mid,ans=r[head]+1;
				while (ls >= rs) {
					mid = ls + rs >> 1;
					if (cal(i,mid) < cal(que[head],mid)) ls = mid-1;
					else ans = mid, rs = mid+1;
				}
				r[head] = ans; l[++head] = ans-1; r[head] = 1; que[head] = i;
			} else que[++head] = i, l[head] = i, r[head] = 1;
		}
	}
	
	for (int i=1;i<=n;i++) printf("%d\n",max(f[i]-arr[i],0));
	return 0;
}

【BZOJ 1563】[NOI2009] 诗人小G

题目传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=1563

决策单调性

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define LD long double
#define LL long long
#define abs(x) ((x)>0?(x):-(x))
using namespace std;

const int MAXN = 100000+9;
const LD EPS = 1e-8;
const LD MX = 1e18+EPS;

int arr[MAXN],n,L,p,l[MAXN],r[MAXN],que[MAXN],head,tail;
LD f[MAXN];
char pat[50];

inline LD cal(int a, int b){
	return f[b]+pow((LD)abs(arr[a]-arr[b]+a-b-1-L),p);
}

int main(){
	int T; cin>>T;
	while (T--) {
		scanf("%d%d%d",&n,&L,&p);
		for (int i=1;i<=n;i++) scanf("%s",pat+1), arr[i] = arr[i-1] + strlen(pat+1);
		l[head=tail=0] = 1; r[0] = n; f[0] = 0; que[0] = 0;
		for (int i=1;i<=n;i++) {
			while (r[tail] < i) tail++;
			f[i] = cal(i,que[tail]);
			if (cal(r[head],que[head]) < cal(r[head],i)) continue;
			else {
				while (head >= tail && cal(l[head],que[head]) >= cal(l[head],i)) head--;
				if (head >= tail) {
					int ls=l[head],rs=n,ans=0,mid;
					while (ls <= rs) {
						mid = ls + rs >> 1;
						if (cal(mid,que[head]) < cal(mid,i)) ans = mid, ls = mid+1;
						else rs = mid-1;
					}
					r[head] = ans; l[head+1] = ans+1; r[head+1] = n;
				} else l[head+1] = 1, r[head+1] = n;
				que[++head] = i; 
			}	
		}
		if (f[n] <= MX) printf("%lld\n",(LL)(f[n]+EPS));
		else printf("Too hard to arrange\n");
		puts("--------------------");
	}
	return 0;
}