2019.09.08【NOIP提高组】模拟 A 组

T1:这是一道规律题,但是我没有想出来。

首先我们发现所有的家庭一定是绕圈放置时答案才是最优的,由此我们可以手玩几个小数据来推出规律。

正解的规律是对于一个正六边形:我们第一次可以花费1的代价扩展它的一条边,产生k-1个新的格子(k代表边长);第二次可以花费1的代价扩展它的第二条边,这时会产生新的k个格子;以此类推,第三、第四、第五条边都是花费1的代价产生k个新的格子,但是第六条边时花费1的代价产生k+1个新的格子。

所以我们首先找到一个面积不超过n的最大的正六边形,然后枚举要扩展它的几条边才能容下n个家庭,这样就可以算出答案了。

代码如下:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#define ll long long

ll n,ans;
int main()
{
//freopen("wall.in","r",stdin);
//freopen("wall.out","w",stdout);
ll k,s;
scanf("%lld",&n);
k=1;s=0;
while(3*k*(k-1)+1<=n)k++;k--;
s=3*k*(k-1)+1;ans=6*k;
if(s>=n){printf("%lld",ans);return 0;}
s=s+k-1;ans++;
if(s>=n){printf("%lld",ans);return 0;}
s=s+k;ans++;
if(s>=n){printf("%lld",ans);return 0;}
s=s+k;ans++;
if(s>=n){printf("%lld",ans);return 0;}
s=s+k;ans++;
if(s>=n){printf("%lld",ans);return 0;}
s=s+k;ans++;
if(s>=n){printf("%lld",ans);return 0;}
s=s+k+1;ans++;
if(s>=n){printf("%lld",ans);return 0;}
}

T2:这题我当场就想出正解了,但是还有一个细节没有处理好。

首先我们从f[i]想i连边,边权为D[f[i]]-C[i],然后我们发现整个图就是一个环套树。接着我们就可以用类似拓扑的方法搞定树的答案(即选最大的边乘上a[f[i]])。然后一个环上一定要删掉一条边,那么我们就选择删掉收益最小的那一条边,然后环就变成了一棵树,用树的方法处理就好了。

注意:1、自环的情况。

2、我们其实可以把所有的物品取剩只有1个时再来割环边,我比赛时就错了这个地方。

T3:这一题不难,但是考思维。

首先我们枚举p串,这里注意p串的长度一定要是n的约数,所以枚举的复杂度是O(n*logn)的。

接着我们可以取件dp,一开始设f[i][j][k]表示i~j这一个区间,去掉所有完整的串之后剩下的几个部分匹配到p的第k位是否可行。

然后我们又可以发现其实k=(j-i+1)*len(len是p的长度),这个想一想就清楚了。所以现在只剩下i、j两维。

接着我们就枚举l表示k+1位匹配的位置,这时又注意到l=j+1+x*len(这个想一想也可以知道为什么),所以l的枚举是O(logn)的。

综上所述,总的时间复杂度是O(n*logn*n^2*logn)=O(n^3*(logn)^2)。有点大,但是优化一下能过。

发布了149 篇原创文章 · 获赞 24 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/chiyankuan/article/details/100705032