今天挂得还是比较惨的。
先讲一下题目大意吧。
第一题:给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;
}
#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;
}