2023.8.15模拟赛题解
模拟赛题解
P7382[COCI2018-2019#6] Simfonija
转化题意,就是钦定一个整数
思路
首先,
如果直接枚举求的话时间复杂度为
假设中位数为
-
是奇数,求的是 。
比 小的数有 ,比 大的数就有 ,其中 。于是就可以转化成求 和 的和的最小值。
我们取出两个式子中的两边一项 和 ,求 ,那么一定满足 。
设 则有 。同理选出 和 ,也能得出类似的结论...因此最小值为
。 -
同理如果
是偶数,可以推得所求的值就是 。
总复杂度为
代码很简单,就不贴了,应该也比较好写。
P6346[CCO2017]专业网络
思路
一个显然的思路是:直接根据
尝试改进这个思路,根据正难则反,我们可以从后往前考虑前面所有人都是花钱购买的这种前提下,当前这个人是否仍需花钱购买。
如果前面所有人加上后面必须购买的人的总和仍然小于当前这个人的
- 直接购买他
- 购买那些本来可以免费结交的人,使得他可以免费结交。
最优方法一定是购买所有满足以上两种情况之一的人中,花钱最少的那个,这样当前这个人就可以结交了。这个过程可以用堆实现。
这种策略的好处是一直保持在一个既花钱少又能保持人数多的状态,如果这种状态仍然小于当前这个人的要求
代码略过,很好写。
经验题
CF1251E1 Voting (Easy Version)
CF1251E2 Voting (Hard Version)
P5999 [CEOI2016] kangaroo
清奇的 dp 题,总之是好题,参考了 Mfeitveer 大佬的题解。
思路
将袋鼠每次跳的过程抽象一下,就变成若干个连通块通过增加和合并最终变成一块。
对于本题只有这两种操作,所以就不难设计状态。令
- 将当前元素单独作为新的一块,那么除了
的左侧和 的右侧都可以放,设合法方案数为 ,则有 - 合并其中两个连续块为一块,选定两个联通块都可以合并,原有
个块,因此方案数为 ,则有
注意需要特判
代码
#include<iostream>
using namespace std;
typedef long long ll;
const int N=2010,mod=1e9+7;
int n,s,t;
ll f[N][N];
int main()
{
cin>>n>>s>>t;
f[1][1]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==s||i==t)
{
(f[i][j]+=f[i-1][j-1]+f[i-1][j])%=mod;
continue;
}
int res=(i>s)+(i>t);
(f[i][j]+=f[i-1][j-1]*(j-res)+f[i-1][j+1]*j)%=mod;
}
cout<<f[n][1];
return 0;
}
其他类似题目
CF704B Ant Man
P9197[JOI Open 2016]摩天大楼
P5967[POI2016]Korale
参考 zzz 学长的博客
简单思路
分成两个问题解决:
- 求第
小值 - 求第
小值对应的集合
对于第一问:
由于我们只是求第
首先按照权值排序。设这个二元组为
对于第二位
设上一问求得的答案为
两部分时间复杂度都是
代码
不开 反正我没过去。
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int n,k,a[N],b[N];
typedef pair<ll,int>PLI;
#define x first
#define y second
priority_queue<PLI,vector<PLI>,greater<PLI>>q;
ll ans,cnt;
int read()
{
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return x;
}
void write(ll x)
{
if(x>9)write(x/10);
putchar(x%10+'0');
}
int mn[N<<2];
#define ls u<<1
#define rs u<<1|1
void build(int u,int l,int r)
{
if(l==r)return mn[u]=a[l],void();
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
mn[u]=min(mn[ls],mn[rs]);
}
int query(int u,int l,int r,int pl,ll x)
{
if(pl<=l)
{
if(mn[u]>x)return 0;
if(l==r)return l;
}
int mid=(l+r)>>1;
if(pl<=mid)
{
int t=query(ls,l,mid,pl,x);
if(t)return t;
}
return query(rs,mid+1,r,pl,x);
}
int top,stk[N];
void dfs(int l,ll res)
{
if(!res&&!--cnt)
{
write(ans),putchar('\n');
for(int i=1;i<=top;i++)write(stk[i]),putchar(' ');
exit(0);
}
for(int i=l+1;i<=n;i++)
{
i=query(1,1,n,i,res);
if(!i)return;
stk[++top]=i;
dfs(i,res-a[i]);
top--;
}
}
int main()
{
n=read(),k=read()-1;
if(!k)return puts("0"),0;
for(int i=1;i<=n;i++)b[i]=a[i]=read();
sort(b+1,b+1+n);
q.push({b[1],1});
for(int i=1;i<=k;i++)
{
PLI t=q.top();q.pop();
if(t.x==ans)cnt++;
else ans=t.x,cnt=1;
if(t.y==n)continue;
t.x+=b[++t.y];
q.push(t);
t.x-=b[t.y-1];
q.push(t);
}
build(1,1,n);
dfs(0,ans);
return 0;
}
后记:感觉这道题还是很有价值和难度的,自己也没有完全理解透彻,因此看到这里的大佬们最好也只做个参考。有锅我背,有您的高见我不胜感激。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】