虽然说是题解,但是并没有贴代码……
因为只写了部分的题,剩下的题因为种种原因 (太懒了) 没有写代码,于是想着全部都不贴好了qwq。
最后的排名是 59 59 59,在这里记录一下。
比赛传送门
枚举每种饮料,求出只喝这种需要的数量,更新一下答案即可。
枚举每一科成绩即可,可以注意到,对于同一个绩点,只需要枚举成绩为该绩点对应的最低分就够了。
一开始以为是什么神奇的数论,写了发贪心交上去WA掉了嘤嘤嘤。
然后一看数据范围, a , b a,b a,b 只有 1000 1000 1000,于是直接写一发dp就可以了,令 f [ i ] [ j ] f[i][j] f[i][j] 表示 a = i , b = j a=i,b=j a=i,b=j 时的最优解,那么有: f [ i ] [ j ] = max ( f [ i − 1 ] [ j ] , f [ i ] [ j − 1 ] ) + [ gcd ( i , j ) = 1 ] f[i][j]=\max(f[i-1][j],f[i][j-1])+[\gcd(i,j)=1] f[i][j]=max(f[i−1][j],f[i][j−1])+[gcd(i,j)=1]。
先枚举作为城市的点,可以算出起点到该点需要的时间。
产生新的人口时,肯定贪心地让它去附近 a [ i ] [ j ] a[i][j] a[i][j] 最大的点,就这样模拟一下即可。
由于 a i a_i ai 从外到内不减,所以对于第 i i i 层的黑段,不存在两个黑段同时与第 i + 1 i+1 i+1 层的黑段相连,所以这是一个森林的形态。
连通块数=点数-边数,特别的,第 n n n 层的贡献为 a [ n ] 2 \dfrac {a[n]} 2 2a[n],考虑第 i i i 层的贡献。
考虑第 i + 1 i+1 i+1 层的一个黑段与第 i i i 层的黑段相交的概率。对于第 i i i 层来说,一个黑段加一个白段为一个循环,长度为 2 a [ i ] \dfrac 2 {a[i]} a[i]2,考虑在这段内一个 i + 1 i+1 i+1 层的黑段与第 i i i 层的黑段不相交的概率,那么它能选择起点的区间长度为 1 a [ i ] − 1 a [ i + 1 ] \dfrac 1 {a[i]}-\dfrac 1 {a[i+1]} a[i]1−a[i+1]1,除以总长度得到概率 a [ i + 1 ] − a [ i ] 2 a [ i + 1 ] \dfrac {a[i+1]-a[i]} {2a[i+1]} 2a[i+1]a[i+1]−a[i],则相交的概率为 a [ i + 1 ] + a [ i ] 2 a [ i + 1 ] \dfrac {a[i+1]+a[i]} {2a[i+1]} 2a[i+1]a[i+1]+a[i],再乘上黑段数量 a [ i + 1 ] 2 \dfrac {a[i+1]} 2 2a[i+1] 得到总概率也是总边数期望 a [ i + 1 ] + a [ i ] 4 \dfrac {a[i+1]+a[i]} 4 4a[i+1]+a[i]。
而第 i i i 层的贡献:点数 − - − 边数就是 a [ i ] 2 − a [ i + 1 ] + a [ i ] 4 = a [ i ] − a [ i + 1 ] 4 \dfrac {a[i]} 2-\dfrac {a[i+1]+a[i]} 4=\dfrac {a[i]-a[i+1]} 4 2a[i]−4a[i+1]+a[i]=4a[i]−a[i+1]。
所有层的贡献加起来就是答案,即 a [ 1 ] + a [ n ] 4 \dfrac {a[1]+a[n]} 4 4a[1]+a[n]。
可以将点分为四类,即按照 c n t cnt cnt 的大小分类。
在每一类点中,再考虑其与原点的距离,那么每一类点可以分为若干层,每一层距离相同。
那么维护一个堆,堆内存每一类点离原点最近的那一层,然后每次取出距离 × c n t \times cnt ×cnt 最小的层贡献一下答案,然后将该类中的后一层加入堆中。
可以发现,对于一类点,统计其前 t t t 层的点数,大概是个与 t t t 相关的等差数列的公式,即包含 t 2 t^2 t2 这一项,所以增长速度很快,于是总时间复杂度只需要 O ( k ) O(\sqrt k) O(k)。
细节比较多,做法也和官方题解有点差异,顺手贴下代码:
#include
#include
#include
using namespace std;
#define ll long long
int T;ll a[10],k,ans,tot;
struct node{ll bel,dis,val;};
struct heap{
node dui[10];int t;
void init(){t=0;}
void add(ll bel,ll dis,ll val){
dui[++t]=(node){bel,dis,val};
for(int i=t-1;i>=1;i--)
if(dui[i+1].val<dui[i].val)swap(dui[i],dui[i+1]);
else break;
}
node pop(){
node re=dui[1];t--;
for(int i=1;i<=t;i++)dui[i]=dui[i+1];
return re;
}
}dui;
int main()
{
scanf("%d",&T);while(T--)
{
for(int i=1;i<=4;i++)scanf("%lld",&a[i]);scanf("%lld",&k);
a[5]=1000000000000000000ll;dui.init();
dui.add(1,0,0);dui.add(2,a[1]+1,(a[1]+1)*3);dui.add(3,a[2]+1,(a[2]+1)*2);dui.add(4,a[3]+1,a[3]+1);
ans=tot=0;
while(tot<k)
{
node x=dui.pop();
ll i=x.bel,dis=x.dis,val=x.val,len;
if(x.dis<=a[i])
{
if(i==1&&dis==0)tot++;
else
{
len=dis+1;
if(i>1&&dis-a[i-1]<=a[i-1])len-=a[i-1]-(dis-a[i-1])+1;
if(tot+4*len-4> k)ans+=(k-tot)*x.val,tot=k;
else tot+=4*len-4,ans+=(4*len-4)*x.val;
}
}
else
{
len=a[i]-(dis-a[i])+1;
if(i>1&&dis-a[i-1]<=a[i-1])len-=a[i-1]-(dis-a[i-1])+1;
if(tot+4*len>k)ans+=(k-tot)*x.val,tot=k;
else tot+=4*len,ans+=4*len*x.val;
}
x.dis++;if(x.dis>2*a[i])continue;
x.val=x.dis*(4-x.bel+1);dui.add(x.bel,x.dis,x.val);
}
printf("%lld\n",ans);
}
}
可以比较容易发现一个网络流做法,先二分一个时间,然后以每个位置作为一个点,有窗户的位置与原点连边,流量为初始蚊子数,以及每个点都与汇点连边,流量为 1 1 1,最后窗户与在时间内能到达的点连边,流量无限。
但是由于总点数太大,会T的半分没有。
考虑到很多点的连边其实是相同的,我们可以将这些点合并起来,然后将他们的合并点与汇点连边,流量为这些点的点数。
具体来说,设 f [ i ] [ s t a ] f[i][sta] f[i][sta] ,其中 s t a sta sta 是一个二进制数表示状态,第 i i i 位为 1 1 1 表示在 i i i 时刻内能到达第 i i i 个窗户,然后 f [ i ] [ s t a ] f[i][sta] f[i][sta] 表示这样的点的数量,每次二分时 n m k nmk nmk 求出 f f f,然后建图泡网络流即可。
推柿子:
S ( n ) = ∑ i = 1 n ∑ j = 1 i j [ gcd ( j , i j ) = 1 ] = ∑ i = 1 n i ∑ j = 1 ⌊ n i ⌋ [ gcd ( i , j ) = 1 ] = ∑ k = 1 n μ ( k ) ∑ i = 1 ⌊ n k ⌋ i k ∑ j = 1 ⌊ n i k 2 ⌋ 1 = ∑ k = 1 n μ ( k ) ∑ i = 1 ⌊ n k ⌋ i k ⌊ n i k 2 ⌋ \begin{aligned} S(n)&=\sum_{i=1}^n\sum_{j=1}^i j [\gcd(j,\frac i j)=1]\\ &=\sum_{i=1}^n i\sum_{j=1}^{\lfloor \frac n i \rfloor} [\gcd(i,j)=1]\\ &=\sum_{k=1}^n\mu(k)\sum_{i=1}^{\lfloor \frac n k \rfloor} ik \sum_{j=1}^{\lfloor \frac n {ik^2} \rfloor}1\\ &=\sum_{k=1}^n\mu(k)\sum_{i=1}^{\lfloor \frac n k \rfloor} ik \lfloor \frac n {ik^2} \rfloor\\ \end{aligned} S(n)=i=1∑nj=1∑ij[gcd(j,ji)=1]=i=1∑nij=1∑⌊in⌋[gcd(i,j)=1]=k=1∑nμ(k)i=1∑⌊kn⌋ikj=1∑⌊ik2n⌋1=k=1∑nμ(k)i=1∑⌊kn⌋ik⌊ik2n⌋
可以发现,当 k > n k>\sqrt n k>n 或 i > ⌊ n k 2 ⌋ i>\lfloor \dfrac n {k^2} \rfloor i>⌊k2n⌋ 时,后面的 ⌊ n i k 2 ⌋ \lfloor \dfrac n {ik^2} \rfloor ⌊ik2n⌋ 必然为 0 0 0,所以可以更改一下枚举上限:
= ∑ k = 1 n μ ( k ) k ∑ i = 1 ⌊ n k 2 ⌋ i ⌊ n i k 2 ⌋ \begin{aligned} &=\sum_{k=1}^{\sqrt n} \mu(k)k \sum_{i=1}^{\lfloor \frac n {k^2} \rfloor} i \lfloor \frac n {ik^2} \rfloor\\ \end{aligned} =k=1∑nμ(k)ki=1∑⌊k2n⌋i⌊ik2n⌋
设 G ( n ) = ∑ i = 1 n i ⌊ n i ⌋ G(n)=\sum_{i=1}^n i\lfloor \dfrac n i \rfloor G(n)=∑i=1ni⌊in⌋,带入得:
= ∑ k = 1 n μ ( k ) k G ( ⌊ n k 2 ⌋ ) =\sum_{k=1}^{\sqrt n} \mu(k)k G(\lfloor \frac n {k^2} \rfloor) =k=1∑nμ(k)kG(⌊k2n⌋)
发现 G G G 是可以用整除分块求的,然后答案也可以用整除分块求,于是就做完了,时间复杂度为:
∑ i = 1 n n i 2 = n ∑ i = 1 n 1 i = n ln n \sum_{i=1}^{\sqrt n} \sqrt{\frac n {i^2}}=\sqrt n\sum_{i=1}^{\sqrt n} \frac 1 i=\sqrt n\ln\sqrt n i=1∑ni2n=ni=1∑ni1=nlnn