P2119
0.前言
如果你不知道怎么推式子,前面的人已经说的很清楚了,%%%
本题只要把式子推出来,一切都好说
因此,我只建议没听懂一长串balabala说怎么递推的蒟蒻比如我阅读这篇题解。
1.分析
先引用一下楼顶dalao的一段话:
首先可以发现每个 $x$ 都小于 $n$ ,而 $n$ 最大值只是15000,所以可以开一个桶来存每个魔法值出现的次数
回忆一下3个约束条件
$ xa<xb<xc<xd ① $
$ xb−xa=2(xd−xc) ② $
$ xb−xa<(xc−xb)/3 ③ $
现在魔改一下这三个式子
设$ t=xd−xc $
所以②可化为$ xb−xa=2t ④ $
将④代入③
$ 2t<(xc−xb)/3 $
移项一下,就变成
$ 6t<xc−xb ⑤ $
再魔改一下
设$ 6t+k=xc−xb $(就是把差的部分补上去)
于是可以画出来一个图
显然,$xa$ 的最小值为1,$xd$ 的最大值为n。
到这里,像我一样的蒟蒻还看得懂
但接下来
由图可得AD=9t+k所以我们可以尝试着枚举t用t来表示各个魔法值的值由上易得t的范围为1<=t<=(n?1)/9在代码中为了避免除法写成t?9<n再枚举D因为我们已经枚举出了t所以C的值是可以直接算出来的C=D?t又因为使ABCD满足条件的k的最小值为1,所以对于当前的C和D最大的A和B为……(省略200字)
不管你看没看懂,反正我没看懂。甚至写完还是不懂QAQ
所以,为了广大蒟蒻的人身安全,我决定解释一下枚举的过程。
2.实现
int main
前,开数组
x[15005],f[40005],q[15005],qa[15005],qb[15005],da[15005],db[15005],dc[15005],dd[15005],ddt[15005];
// 桶 输入 合法的AB物品组数 权A 权B 大小为i的A,B,C,D物品数量 至i合法的C,D组数
int main
部分,枚举 $t$,使 $t\lt n/9$,非常合理。
然后,枚举 $B$。(此处和原题解不同,因为本人认为这样写更好理解)
首先,考虑一个数作为 $xb$ 要满足的条件。
很简单,即
for(int b=t*2+1;b<n-t*7;b++)
这时,我们可以开一个数组 $q$,记录从 $b$ 开始,合法的AB物品组数,即 $SumA∗SumB$。
同时为了以后方便回推 $xa$,$xb$,记录每组物品中A,B物品的数量,称为 $qb$,$qa$。
最终算数量时,因为每个A对 $qa$ 个B,所以可以以B的数量作为A的权,即 $qa$ (权A)。B同理。
代码片段如下:
for(int b=t*2+1;b<n-t*7;b++)q[b]=q[b-1]+x[b-t*2]*x[b],qa[b-t*2]+=x[b],qb[b]+=x[b-t*2];
下一步,枚举C,D物品。
C物品数量为 $q*x_d$,D同理。
此时需统计合法的C,D组数,即 $ddt$。
代码片段如下:
for(int d=t*9+1;d<=n;d++){
dd[d]+=q[d-t*7-1]*x[d-t];
dc[d-t]+=q[d-t*7-1]*x[d];
ddt[d-t*7-1]+=x[d]*x[d-t];
}
最后,算AB,初始化。
3.代码
先进食后人:
$b-a=2(d-c)$!别看反了
#include<bits/stdc++.h>
using namespace std;
int n,m,x[15005],f[40005],q[15005],qa[15005],qb[15005],da[15005],db[15005],dc[15005],dd[15005],ddt[15005];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>f[i],x[f[i]]++;
for(int t=1;t*9<n;t++){
q[t*2]=0;
for(int b=t*2+1;b<n-t*7;b++)q[b]=q[b-1]+x[b-t*2]*x[b],qa[b-t*2]+=x[b],qb[b]+=x[b-t*2];
for(int d=t*9+1;d<=n;d++){
dd[d]+=q[d-t*7-1]*x[d-t];
dc[d-t]+=q[d-t*7-1]*x[d];
ddt[d-t*7-1]+=x[d]*x[d-t];
}
for(int i=n-t*7-1;i>t*2;i--)ddt[i]+=ddt[i+1],da[i-t*2]+=ddt[i]*qa[i-t*2],db[i]+=ddt[i]*qb[i];
memset(ddt,0,sizeof(ddt));
memset(qa,0,sizeof(ddt));
memset(qb,0,sizeof(ddt));
}
for(int i=1;i<=m;i++)cout<<da[f[i]]<<' '<<db[f[i]]<<' '<<dc[f[i]]<<' '<<dd[f[i]]<<'\n';
}
4.结语
首先,希望本题解对你有所帮助。
如果你对本题解有任何疑问,请评论,我会第一时间改正的QAQ
最后麻烦管理大大给过