【BZOJ 1833】[ZJOI2010] count 数字计数

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

仍然是数位dp

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

const int MAXN = 20;

LL f[MAXN][MAXN][MAXN],ans[MAXN],p[MAXN];

inline void prework(){
	p[0] = 1; p[1] = 10; 
	for (int i=2;i<=12;i++) p[i] = p[i-1]*10;
	for (int i=0;i<=9;i++) f[1][i][i] = 1;
	for (int k=2;k<=12;k++) {
		for (int i=0;i<=9;i++) {
			for (int j=0;j<=9;j++) {
				for (int h=0;h<=9;h++) {
					f[k][i][h] += f[k-1][j][h];
				}
			}
			f[k][i][i] += p[k-1];
		}
	}
}

inline void cal(LL w, int t){
	if (!w) return;
	else {
		int tot = 0, arr[20]; LL tmp = w;
		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++) 
			for (int k=0;k<=9;k++) ans[k] += f[i][j][k]*t;
		for (int i=tot;i;i--) {
			for (int j=(i==tot?1:0);j<=arr[i]-(i==1?0:1);j++) 
				for (int k=0;k<=9;k++) ans[k] += f[i][j][k]*t;
			if (i>1) ans[arr[i]] += (tmp % p[i-1] + 1)*t;
		}
	}
}

int main(){
	prework();
	LL a,b; cin>>a>>b;
	cal(b,1); 
	cal(a-1,-1);
	for (int i=0;i<9;i++) printf("%lld ", ans[i]);
	printf("%lld",ans[9]);
	return 0;
} 

【HDU 3555】Bomb

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

数位dp

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

const int MAXN = 30;

LL f[MAXN][MAXN][2];

inline LL read(){
	char c=getchar(); LL 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 prework(){
	for (int i=0;i<=9;i++) f[1][i][0] = 1;
	for (int k=2,tmp=0;k<=28;k++) {
		for (int i=0;i<=9;i++) {
			for (int j=0;j<=9;j++) {
				if (i == 4 && j == 9) f[k][i][1] += f[k-1][j][0];
				else f[k][i][0] += f[k-1][j][0];
				f[k][i][1] += f[k-1][j][1];
			}
		}
	}
}

inline LL cal(LL w){
	if (!w) return 0;
	else { 
		int tot = 0, arr[20]; LL ret = 0, tmp = w, t2;
		memset(arr,0,sizeof(arr));
		while (w) arr[++tot] = w % 10, w /= 10;
	
		for (int i=1;i<tot;i++) for (int j=1;j<=9;j++) ret += f[i][j][1];
		for (int i=1;i<arr[tot];i++) ret += f[tot][i][1];
		for (int i=tot-1;i;i--){
			for (int j=0;j<arr[i];j++) ret += f[i][j][1];
			if (arr[i+1] == 4 && arr[i] == 9) {
				ret += tmp%(LL)(pow(10,i-1)+0.1)+1;
				break;
			}
		}
		return ret;
	}
}

int main(){
	prework();
	int T; T = read();
	while (T--) {
		LL a=read();
		cout<<cal(a)<<endl;
	}
	return 0;
} 

【BZOJ 1026】[SCOI2009] windy数

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

数位DP

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

const int MAXN = 20;

int f[MAXN][MAXN],a,b;

inline void prework(){
	for (int i=0;i<=9;i++) f[1][i] = 1;
	for (int k=2;k<=10;k++) {
		for (int i=0;i<=9;i++) {
			for (int j=i+2;j<=9;j++) f[k][i] += f[k-1][j];
			for (int j=i-2;j>=0;j--) f[k][i] += f[k-1][j];
		}
	}
}

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

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

【NOI六连测】[D6T1] 互质

题目传送门:http://pan.baidu.com/s/1eR1sqXk
离线版题目:http://paste.ubuntu.com/18699825/
数据传送门:http://pan.baidu.com/s/1o8pgYZg

这个题目,暴力的状压很容易想到,然而质因数太多,数组开不下 QAQ
于是考试的时候,码个暴力就闪人了。一看题解,真的是好妙啊!o( ̄▽ ̄)ブ

我们只拆分33以内的质因数,这里只有12个,可以承受。
这么干,还有一个好处:对于一个1k以内的数,超过33的质因数只可能有一个
也就是说,我们对于任意一个数,分两种情况讨论:
1)只有33以内的质因数:这样的话,直接暴力转移即可
2)有33以上的质因数:将拥有相同的、大于33的质因数的数存成一组,像分组背包一样一起转移
因为大于33的质因数只可能有一个,而相同的存在了一起,所以只要保证小于34的质因数不重合即可

此题真的是妙啊!

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

const int MAXN = 5000;
const int LIM = 4500;
const int N = 12;

int sed[]={0,2,3,5,7,11,13,17,19,23,29,31,33};
int n,que[MAXN][MAXN],cnt[MAXN];
int t1[MAXN],t2[MAXN],*f,*g;

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("prime.in","r",stdin);
	freopen("prime.out","w",stdout);
	n = read();
	f=t1; g=t2;
	
	for (int i=1,a;i<=n;i++){
		a = read();
		int tmp = a, buf = 0;
		for (int i=1;i<=N;i++) if (!(tmp%sed[i])) {
			while (!(tmp%sed[i])) tmp /= sed[i];
			buf |= 1<<(i-1);
		} 
		if (tmp != 1) que[tmp][++cnt[tmp]] = buf;
		else for (int i=1;i<=LIM;i++) if (!(i&buf)) 
			f[i|buf] = max(f[i|buf], f[i]+1);
	}
	
	for (int i=1;i<=1000;i++){
		for (int k=1;k<=LIM;k++) g[k] = f[k];
		for (int j=1;j<=cnt[i];j++)	for (int k=1;k<=LIM;k++)
			if (!(k&que[i][j])) g[k|que[i][j]] = max(g[k|que[i][j]], f[k]+1);		
		swap(g,f);
	}
	
	int vout = 1;
	for (int i=1;i<=LIM;i++)
		vout = max(vout, f[i]);
	printf("%d\n",vout);
	
	return 0;
}	

—————————— UPD 2017.2.1 ——————————
总感觉这个题DLX可以暴力过的样子
有没有同学有空写写啊!

【NOI六连测】[D4T1] 数学

题目传送门:http://pan.baidu.com/s/1eRRG6Wy
离线版题目:http://paste.ubuntu.com/18459243/
数据传送门:http://pan.baidu.com/s/1miarNuS

这一道题目,真的是十分可惜。考试前一个小时,码完了O(K*n^2) 的暴力DP,但一直到考试结束前9分钟才推出斜率DP的式子。
本来以为斜率DP可以随便切了QAQ,现在来看,代码实现确实不恼火了,但是推式子还是很恼火啊!
这一道题目,式子推出来之后,也就没什么好说的了。先贴一贴斜率DP的代码,后续再来更决策单调,和神奇的二分的代码。

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

const int MAXN = 200000+9;
const int K = 50+9;

double x[K][MAXN/2],y[K][MAXN/2],rev[MAXN],ret,arr[MAXN];
int AA[MAXN],n,k,l[K],r[K],pos[K][MAXN/2]; 

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

#define slope(t,b,a) (y[t][a]-y[t][b])/(x[t][a]-x[t][b])

inline void update(int t, double X, double Y, int i){
	int tmp = r[t]+1; x[t][tmp]=X; y[t][tmp]=Y;
	while (l[t] < r[t]) if (slope(t,r[t],tmp) > slope(t,r[t]-1,r[t])) r[t]--;
		else break;
	x[t][++r[t]] = X; y[t][r[t]] = Y; pos[t][r[t]] = i;
}

inline double Get(int t, int w){
	while (l[t] < r[t]) if (slope(t,l[t],l[t]+1) > rev[w+1]) l[t]++;
		else break;
	return (arr[w]-arr[pos[t][l[t]]])*rev[w+1]+y[t][l[t]];
}

int main(){
	freopen("math.in","r",stdin);
	freopen("math.out","w",stdout);
	n = read(); k = read()-1;
	for (int i=1;i<=n;i++) AA[i] = read();
	for (int i=1;i<=n;i++) arr[i] = (double)AA[i]+arr[i-1];
	for (int i=n;i;i--) rev[i] = rev[i+1] + (double)1/AA[i]; 
	for (int i=1;i<=n;i++) ret += (double)AA[i]*rev[i];
	for (int i=0;i<=k;i++) l[i] = 1;
	
	for (int w=1;w<n;w++){
		for (int i=1;i<k;i++) if (r[i]) 
			update(i+1,arr[w],Get(i,w),w);
		update(1,arr[w],arr[w]*rev[w+1],w);
	} 
	double vout = 0;
	for (int i=l[k];i<=r[k];i++)
		vout = max(vout, y[k][i]);
	printf("%.15lf\n",ret - vout);
	return 0;
}