版权声明:转载请注明原出处啦(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/82930558
题目:luogu2119.
题目大意:给定一个序列,要求求出满足,且的a,b,c,d的数量.
首先这道题可以直接用一个桶,先把所有数塞进这个桶里.
然后我们可以开始枚举答案.
但我们发现,所以我们可以省去以为的枚举,做到枚举,实测在洛谷上能拿到85分.
到这一步优化的代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=15000,M=40000;
int n,m,x[M+9];
LL num[N+9][4],cnt[N+9];
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
scanf("%d",&x[i]);
cnt[x[i]]++;
}
}
Abigail work(){
for (int a=1;a<=n;a++)
for (int b=a+1;b<=n;b++)
for (int c=b+1;c<=n;c++){
if (b-a&1||3*b-3*a>=c-b) continue;
int d=b-a+c*2>>1;
LL ans=cnt[a]*cnt[b]*cnt[c]*cnt[d];
num[a][0]+=ans;num[b][1]+=ans;num[c][2]+=ans;num[d][3]+=ans;
}
for (int i=1;i<=n;i++)
for (int j=0;j<4;j++)
num[i][j]/=cnt[i]?cnt[i]:1;
}
Abigail outo(){
for (int i=1;i<=m;i++){
for (int j=0;j<3;j++)
printf("%lld ",num[x[i]][j]);
printf("%lld\n",num[x[i]][3]);
}
}
int main(){
into();
work();
outo();
return 0;
}
接下来的优化需要将变式,改成.
然后我们设,那么,.
然后我们在设,那么就可以画一个图:
我们发现,由于所有数都是整数,所以k的最小值为1.
现在我们枚举t和,我们就可以计算出,然后C的最小值为,D的最小值为.
我们发现若t和确定了,那么我们就可以确定只有k的问题了,我们发现k取[1,n-9t]内的任意一个数都是可以的,那我们就可以维护一个前缀和数组vis[i][t]表示c为i,d为i+t的时候有多少种.
由于这样会占用很大内存导致MLE,所以我们在推的时候处理,这样就可以确定c和d的数量了.但是要注意,由于我们要边处理边推,所以我们要逆推.
而a和b的确定和c和d很像,换成顺推就可以了.
而这样做的时间复杂度为,还是不能拿到满分.
接下来我们就进行一些细节的优化,我们发现,而,所以我们可以发现其实,所以t只需要枚举到就可以了.但是这样写代码会有除法,比较慢,所以我们写成.
那么这个算法的时间复杂度就是,可以过了,但可能需要一定的常数优化(然而并没有什么可以优化的地方).
所以大致的算法流程如下:
1.枚举.
2.枚举,可以推出C=D-t,之后可以设A为A的最大值,B为B的最大值,得到B=C-6t-1,A=6t-1.
3.在2的同时,记录一个sum初始为0,表示当前D时,A和B的情况有多少种.
4.同样,枚举.
5.同样,到这处理前缀和.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=15000,M=40000;
int n,m,x[M+9],num[4][N+9],cnt[N+9];
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
scanf("%d",&x[i]);
cnt[x[i]]++;
}
}
Abigail work(){
int sum,A,B,C,D;
for (int t=1;t*9<n;t++){
sum=0;
for (D=9*t-2;D<=n;D++){
C=D-t;
B=C-6*t-1;
A=B-2*t; //知道D,计算出A,B,C
sum+=cnt[A]*cnt[B]; //计算当前A和B的情况
num[2][C]+=cnt[D]*sum; //num[2][C]+=cnt[A]*cnt[B]*cnt[C]
num[3][D]+=cnt[C]*sum; //num[3][D]+=cnt[A]*cnt[B]*cnt[D]
}
sum=0;
for (A=n-9*t-1;A;A--){
B=A+2*t;
C=B+6*t+1;
D=C+t; //知道A,计算出B,C,D
sum+=cnt[C]*cnt[D]; //计算当前C和D的情况
num[0][A]+=cnt[B]*sum; //num[0][A]+=cnt[B]*cnt[C]*cnt[D]
num[1][B]+=cnt[A]*sum; //num[1][B]+=cnt[A]*cnt[C]*cnt[D]
}
}
}
Abigail outo(){
for (int i=1;i<=m;i++){
for (int j=0;j<3;j++)
printf("%d ",num[j][x[i]]);
printf("%d\n",num[3][x[i]]);
}
}
int main(){
into();
work();
outo();
return 0;
}