【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;
}

【BZOJ 1042】[HAOI2008] 硬币购物

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

这个题呢,第一眼看到就知道不会做,结果果然只会O(n*logn*t)的dp
题解的话,我们来膜byvoid吧:https://www.byvoid.com/blog/haoi-2008-coin

#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;

const int SGZ = 5;
const int MAXN = 100000+9;
const int LIM = 100000;

int c[SGZ],s,d[SGZ];
LL f[MAXN],vout;

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;
}

void solve(int p, int sz, int w){
	if (p == 5) {
		if (sz & 1) vout -= f[s-w];
		else if (sz) vout += f[s-w];
	} else {
		solve(p+1,sz,w);
		if (w+d[p] <= s) solve(p+1,sz+1,w+d[p]);
	}
}

int main(){
	for (int i=1;i<=4;i++) c[i] = read(); int T = read(); f[0] = 1;
	for (int j=1;j<=4;j++) for (int i=c[j];i<=LIM;i++) f[i] += f[i-c[j]];
	while (T--) {
		for (int i=1;i<=4;i++) d[i] = read(); s = read();
		for (int i=1;i<=4;i++) d[i] = (d[i]+1)*c[i];
		vout = f[s]; solve(1,0,0);
		printf("%lld\n",vout);	
	}
	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;
}

【HDU 1693】Eat the Trees

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1693

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;

const int MAXN = 5000;

LL f[12][12][MAXN];
int MX,n,m,mat[12][12];

int main(){
	int TT; cin>>TT;
	for (int T=1;T<=TT;T++) {
		scanf("%d%d",&m,&n); MX =1<<n+1;
		for (int j=1;j<=m;j++) for (int i=1;i<=n;i++) 
			scanf("%d",&mat[i][j]),memset(f[i][j],0,sizeof(f[i][j]));
		
		
		if (mat[1][1]) f[1][1][3] = 1;
		else f[1][1][0] = 1;
		for (int j=1;j<=m;j++) { 
			for (int i=1;i<n;i++) {
				for (int k=0;k<MX;k++) if (f[i][j][k]) {
					bool up=k&(1<<i+1), left=k&(1<<i);
					if (mat[i+1][j]) {
			 			if (up && left) f[i+1][j][k^(1<<i)^(1<<i+1)] += f[i][j][k];
						else if (up || left) {
							f[i+1][j][k] += f[i][j][k];
							f[i+1][j][k^(1<<i+1)^(1<<i)] += f[i][j][k];	
						} else {
							f[i+1][j][k^(1<<i+1)^(1<<i)] += f[i][j][k];
						}
					} else {
						if (!up && !left) f[i+1][j][k] += f[i][j][k];
					} 
				} 
			}
			for (int k=0;k<MX;k++) if (f[n][j][k] && (k&(1<<n)) == 0) {
				int up = k & 1;
				if (mat[1][j+1]) {
					if (up) {
						f[1][j+1][((k^1)<<1)^1] += f[n][j][k];
						f[1][j+1][((k^1)<<1)^2] += f[n][j][k];
					} else {
						f[1][j+1][(k<<1)^3] += f[n][j][k];
					}
				} else {
					if (!up) f[1][j+1][k<<1] += f[n][j][k];
					else continue;
				}
			}
		}  
		printf("Case %d: There are %I64d ways to eat the trees.\n",T,f[n][m][0]);
	} 
	return 0;
} 

【POJ 2411】Mondriaan’s Dream

题目传送门:http://poj.org/problem?id=2411

轮廓线dp

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;

const int MAXN = (1<<12)+9;

int n,m;
LL f[2][MAXN];

int main(){
	while (scanf("%d%d",&n,&m) && (n || m)) {
		int now=1, pre=0, MX=1<<n;
		memset(f[now],0,sizeof(f[now]));
		f[now][0] = 1;
		
		for (int j=1;j<=m;j++) {
			for (int i=1;i<=n;i++) {
				swap(now, pre);
				memset(f[now],0,sizeof(f[now]));
				for (int k=0;k<MX;k++) if (f[pre][k]) {
					f[now][k^(1<<i-1)] += f[pre][k];
					if (i > 1 && k&(1<<i-2) && !(k&(1<<i-1)))
						f[now][k^(1<<i-2)] += f[pre][k];
				}
			}
		}
		printf("%lld\n",f[now][0]);
 	}
	return 0;
} 

【HDU 2089】不要62

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2089

还是数位dp

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

const int MAXN = 10;

int f[MAXN][MAXN];

inline void prework(){
	for (int i=0;i<=9;i++) f[1][i] = (i != 4);
	for (int k=2;k<=6;k++) {
		for (int i=0;i<=9;i++) {
			if (i == 4) continue;
			else for (int j=0;j<=9;j++) 
				if (i == 6 && j == 2) continue;
				else f[k][i] += f[k-1][j];
		}
	}
}

inline int cal(int w){
	if (!w) return 0;
	
	int ret=0,tot=0,arr[MAXN];
	memset(arr,0,sizeof(arr));
	while (w) arr[++tot] = w % 10, w /= 10;
	
	for (int i=tot-1;i;i--) for (int j=1;j<=9;j++) ret += f[i][j];
	for (int i=tot;i;i--) {
		for (int j=(i==tot?1:0);j<arr[i];j++) 
			if (arr[i+1] == 6 && j == 2) continue;
			else ret += f[i][j];
		if ((arr[i] == 2 && arr[i+1] == 6) || arr[i] == 4) break;
		else if (i == 1) ret ++;
	}
	return ret;
} 

int main(){
	prework(); int a,b;
	while (scanf("%d%d",&a,&b) && (a || b)) 
		printf("%d\n",cal(b)-cal(a-1));	
	return 0;
}