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
最后麻烦管理大大给过

浙公网安备 33010602011771号