2014.8.11 BJOI2014

今天挂得还是比较惨的。


先讲一下题目大意吧。


第一题:给N(N <= 100)种不同面值(<=1000)的硬币(你可以假设每种都有无数多个),有T(<=100000)个询问,问你要组成面值为M(<=10^16),最小要多少个硬币。


第二题:给出x(x<=10^12),问你最小的y,使得φ(y) = x.


第三题,给你一个n(n<=5000)个元素的数列A和一个常数D,求对于每个位置i,有多少种合法的三元组(k,j,l)

一个三元组被称为合法的。当且仅当max(0,i-D) < k <= j <= l < i,且a[k]+a[j]+a[l] = a[i]


我们按题目难度排序。很显然难度是倒序的。


先讲一下我考场时怎么想的吧。

第一题,很容易得到DP式f[i] = min{f[i - A[j]] + 1},然后,我是这么想的。

既然M这么大,很直接的思路就是用矩阵。结果,面值太大了(<=1000)。。一个用到N的矩阵搞不出来。。。想了一会儿后果断放弃,捡了暴力的30分。


第二题,看起来就是数学题。

我们知道的是,φ(n) = π(pi - 1)(pi^(ci-1)).

很直接的想法就是把x给分解质因数。要使得y最小,那么ci肯定尽量为1啦(注意这里。。。)

那么我们对于x的约数i,若(i+1)为质数,则称i为x的伪质因数。

(我漏掉的地方。。)若x mod (2^k) = 0,那么我们此时也要把2^k作为x的伪质因数。。。

接着我们直接爆搜就好了。(剪枝就不用讲了吧)


第三题,看起来像是要用数据结构。于是我光荣跳坑。想了很久的可持久化。空间始终不够。

最后只剩一个多钟去搞60分。。。结果。。。。没有拍。。。你懂的。


题解(我就简洁点了)

第一题,注意到面值<=1000,对于Dp,我们Dp的范围越大,F数组越趋于稳定。事实上我们只需要DP到

max^2就好了。对于询问M,我们选择一定量的max,使得M降到max^2以内,直接+起来就好了。

第二题,上面讲了。

第三题,设g[i] 表示当前合法区间内两个数和为i的方案,f[i]表示区间内单个数为i的个数。

那么我们枚举l,Ans+=g[A[i] - A[l]] + f[A[i] - A[l] - A[l]] + (3 * A[l] = A[i])

你或许会问我最后那个有什么用。我会告诉你这是为了让每一种方案*3倍。

最后我们Ans/3就去重了。


今天暴露的问题:

1:数组空间开小,分析问题不全面。

2:做题时有点心急,敲代码没有注意具体的时间复杂度与空间复杂度。

3:容易陷入死坑。想问题复杂。 

努力方向:

1:注意思维的多样化,不要因为做专题做多了人傻了。

2:敲代码时不要急,思考问题要缜密

3:修改一段代码时注意引起的空间与时间问题。

贴代码

T1

#include
#include
#include

using namespace std;

const int MAXN = 100005;

int F[2000005];
int A[105],N;

int main()
{
	scanf("%d", &N);
	memset(F,255,sizeof F);
	F[0] = 0;
	for(int i = 1;i <= N;i ++) scanf("%d", &A[i]);
	sort(A + 1,A + N + 1);
	for(int i = 1;i <= 1000000;i ++) 
		for(int j = 1;j <= N;j ++) if (i >= A[j] && F[i - A[j]] != -1) 
		{
			if (F[i] == -1) F[i] = F[i - A[j]] + 1; else F[i] = min(F[i],F[i - A[j]] + 1);
		}
	int T;scanf("%d", &T);
	for(int i = 1;i <= T;i ++)
	{
		long long x,ans;scanf("%lld", &x);
		if (x <= 1000000) {printf("%d\n", F[x]);continue;}
		ans = (x - 1000000) / A[N];x -= ans * A[N];
		while (F[x] == -1 && ans) ans ++,x -= A[N];
		if (!ans && F[x] == -1) printf("-1\n"); else
		printf("%lld\n",F[x] + ans);
	}
}

T2

#include
#include
#include
#include

using namespace std;

const int MAXN = 1000005,MAXM = 1005;

map Hash;
bool f[MAXN],bz[MAXM],tr;
long long H,Ok[5005],Inc[5005][50][2],Ans;
int Zh[MAXN],Least[MAXM],tot,N,T,cnt,qc;

struct Node
{
	long long a;int b;
}Count[MAXM];

void Pre_Treat()
{
	N = MAXN - 1;
	for(int i = 2;i <= N;i ++)
	{
		if (!f[i]) Zh[++ tot] = i;
		for(int j = 1;j <= tot;j ++)
		if (i * (long long)(Zh[j]) > N) break; else
		{
			f[Zh[j] * i] = 1;
			if (i % Zh[j] == 0) break;
		}
	}
}

bool chk(long long a)
{
	if (a < MAXN) return !f[a];
	for(int j = 1;j <= tot;j ++)
	if (Zh[j] * (long long)Zh[j] > a) break; else
	if (a % Zh[j] == 0 && a != Zh[j]) return 0;
	return 1;
}

bool Chk(int Now)
{
	for(int i = 1;i <= Inc[Now][0][0];i ++) 
	{
		int j = Inc[Now][i][0];
		if (Least[j] + Inc[Now][i][1] > Count[j].b) return 0;
	}
	for(int i = 1;i <= Inc[Now][0][0];i ++) Least[Inc[Now][i][0]] += Inc[Now][i][1];
	return 1;
}

void Dfs(int Now,long long Tmp)
{
	if (Tmp >= Ans || Tmp > 7 * H) return;
	if (!Now)
	{
		for(int i = 1;i <= qc;i ++) if (Least[i] != Count[i].b) return;
		Ans = Tmp;
		return;
	}
	if (Chk(Now))
	{
		Dfs(Now - 1,Tmp * (Ok[Now] + 1));
		for(int i = 1;i <= Inc[Now][0][0];i ++) Least[Inc[Now][i][0]] -= Inc[Now][i][1];
	}
	Dfs(Now - 1,Tmp);
}

bool cmp(Node a,Node b)
{
	return a.a < b.a;
}

void Work()
{
	scanf("%lld", &H);
	cnt = 0,qc = 0;
	tr = 0;Ans = 1LL << 62;
	memset(bz,0,sizeof bz);memset(Least,0,sizeof Least);memset(Inc,0,sizeof Inc);
	long long tmp = H;
	if (H == 1) {printf("1\n");return;}
	if (chk(H + 1))
	{
		printf("%lld\n",H + 1);return;
	}
	for(int i = 2;(long long)i * i <= H;i ++)
	if (H % i == 0)
	{
		if (!f[i])
		{
			Count[++ qc].a = i;Count[qc].b = 0;
			while (tmp % i == 0) Count[qc].b ++, tmp /= i;
		}
		if (!f[i + 1]) Ok[++ cnt] = i;
		if (chk(H / i + 1)) Ok[++ cnt] = H / i;
	}
	sort(Ok + 1,Ok + cnt + 1);
	if (tmp != 1) Count[++ qc].a = tmp,Count[qc].b = 1;
	for(int i = 1;i <= cnt;i ++)
	{
		tmp = Ok[i];
		for(int j = 1;j <= qc;j ++)
		if (tmp % Count[j].a == 0)
		{
			Inc[i][++ Inc[i][0][0]][0] = j;
			while (tmp % Count[j].a == 0) Inc[i][Inc[i][0][0]][1] ++,tmp /= Count[j].a;
		}
	}
	if (Count[1].a == 2)
	{
		tmp = 2;
		for(int j = 1;j <= Count[1].b;j ++)
		{
			tmp *= 2;
			Ok[++ cnt] = tmp - 1,Inc[cnt][Inc[cnt][0][0] = 1][0] = 1,Inc[cnt][1][1] = j;
		}
	}
	Dfs(cnt,1);
	printf("%lld\n",Ans);
}

int main()
{
	Pre_Treat();
	scanf("%d", &T);
	for(;T;T --) Work();
	return 0;
}
T3
#include
#include
#include
#include

using namespace std;

const int MAXN = 5005,Change_In = 2000005;

int A[MAXN],sum[Change_In * 4 + 5],Count[Change_In * 4 + 4],cnt,N,D;

void Work1()
{
	for(int i = 1;i <= N;i ++)
	{
		int x = max(0,i - D);
		long long Tmp = 0;
		if (i - 1) Count[A[i - 1] + Change_In] ++;
		for(int j = x + 1;j < i;j ++) sum[A[j] + A[i - 1] + Change_In] ++;
		if (x) {
			Count[A[x] + Change_In] --;
			for(int j = x;j < i - 1;j ++) sum[A[x] + A[j] + Change_In] --;
		}
		for(int l = x + 1;l < i;l ++)
		{
			if (A[i] - A[l] + Change_In >= 0) Tmp += sum[A[i] - A[l] + Change_In];
			if (A[l] * 3 == A[i]) Tmp ++;
			if (A[i] - A[l] - A[l] + Change_In >= 0) Tmp += Count[A[i] - A[l] - A[l] + Change_In];
		}
		printf("%lld\n", Tmp / 3);
	}
}

int main()
{
	scanf("%d%d", &N, &D);
	for(int i = 1;i <= N;i ++) scanf("%d", &A[i]);
	Work1();
	return 0;
}

你可能感兴趣的:(总结)