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

      
      
     
     
    
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值