UNR #4
序列妙妙值
题目描述
解法
我真的感觉这题并不简单,但是好像大家都会的样子。
设 表示前 个数划分成 段的最小代价,设 ,转移:
这个转移虽然形式简洁,但是没有什么性质也难以直接套数据结构。不妨先考虑 的部分分,可以维护 个桶,每个桶表示这个 值对应最小的 ,时间复杂度
考虑把上面的做法推广到 ,自然想到值域分块,目的是平衡修改的查询的时间(原来是 的,尝试优化成 ),维护 表示假设 的前 位为 ,已知 的后 位为 ,最小的代价是多少(注意前 位代表较大的数位,前 位的代价在修改时放进 中,后 位的代价在查询时统计)
时间复杂度 ,写完博客突然感觉这题在哪里见过。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 60005;
const int inf = 0x3f3f3f3f;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,k,a[M],dp[M][10],f[1<<8][1<<8];
void upd(int &x,int y) {x=min(x,y);}
int main()
{
n=read();k=read();
for(int i=1;i<=n;i++)
a[i]=read()^a[i-1];
memset(dp,0x3f,sizeof dp);
dp[0][0]=0;
for(int j=1;j<=k;j++)
{
for(int i=0;i<(1<<16);i++)
f[i>>8][i&255]=inf;
for(int i=j;i<=n;i++)
{
for(int k=0;k<(1<<8);k++)
{
int x=(k^(a[i-1]>>8))<<8;
upd(f[k][a[i-1]&255],dp[i-1][j-1]+x);
}
for(int k=0;k<(1<<8);k++)
upd(dp[i][j],f[a[i]>>8][k]+((a[i]^k)&255));
}
}
for(int i=k;i<=n;i++)
printf("%d ",dp[i][k]);
}
网络恢复
题目描述
解法
交互题一定要注意特殊性质的部分分,很多时候有一个特殊性质的做法可以直接推广到正解。
考虑树的部分分,从叶子往上确定整棵树。那么我们给每个点随机一个 以内的权值,如果点 的 是某个 的 ,那么可以认为 是叶子且 直接有边相连,把 删除之后循环这个过程,只消耗一次询问。
上面的做法其实只要无环就可以求出原图的所有边,那么考虑把原图的边划分为若干个无环的子图,对这些子图分别用树的方法就可以得到答案。具体来说我们循环一下过程 次:随机一个边的排列,把这个排列 等分,就获得了 个子图,注意一条边可能被确定多次,需要判断一下,实测可以获得 分。
边数很多时构成环的概率很大,但是由于数据随机的原因,很难有导出子图满足每个点度数都 ,所以我们只需要支持在不存在叶子时,确定某个度数 的点的边即可。可以把所有点都拿出来,然后随机两个点,假设它们之间有边然后断掉,如果此时出现了真的叶子,那么可以判定它们真的有边,就达到了判断环的目的。
所以我们把原图的边直接 等分,然后魔改一下树的做法使其可以支持一些简单环的拆解,可以获得 分。
#include "explore.h"
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
#define vc vector
#define ull unsigned long long
const int M = 50005;
//
int n,m,k,h[M],q[M];vc<ull> a,b;
__gnu_pbds::gp_hash_table<ull,int> id;
__gnu_pbds::gp_hash_table<int,int> e[M];
mt19937_64 X(time(0));mt19937 Y(time(0));
void report(int x,int y)
{
if(x>y) swap(x,y);
if(!e[x][y]) Report(x+1,y+1);
e[x][y]=1;
b[x]^=a[y];b[y]^=a[x];
if(id[b[x]]) q[++k]=x;
if(id[b[y]]) q[++k]=y;
}
void work(int l,int r)
{
vc<int> t;
for(int i=l;i<=r;i++)
t.push_back(i);
b=Query(a,t);
for(int i=0;i<n;i++)
if(id[b[i]]) q[++k]=i;
while(1)
{
if(k)
{
int u=q[k--];
if(b[u]) report(u,id[b[u]]-1);
}
else
{
int l=0;
for(int i=0;i<n;i++)
if(b[i]) h[l++]=i;
if(!l) return ;
while(1)
{
int x=rand()%(l-1)+1,y=rand()%x;
x=h[x];y=h[y];
if(id[b[x]^a[y]] || id[b[y]^a[x]])
{report(x,y);break;}
}
}
}
}
void Solve(int n1,int m1)
{
n=n1;m=m1;
for(int i=0;i<n;i++)
a.push_back(X()),id[a[i]]=i+1;
int bk=(m+49)/50;
for(int i=1;i<=50;i++)
work(i*bk-bk+1,min(i*bk,m));
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2021-08-09 [做题笔记] 浅谈状压dp在图计数问题上的应用
2021-08-09 [2017 山东一轮集训 Day7] 逆序对