十二省联考题解 - JLOI2019 题解

两个T3的难度较大

平均代码量远大于去年省选

套路题考查居多

A

难度等级 1

$n^2$暴力可以拿到$60$分的优秀成绩

然后可以想到把区间异或转化为前缀两点异或

可以想到使用二分答案的方法+可持久化Trie解决,但是时间复杂度为$n\log^2 (4294967295) $

这是唯一一通过不了的$poly(\log)$做法,常数不够优秀的话会得到$60$分,卡一卡说不定可以$80$,理论上能卡到$100$

然后可以通过将二分放在可持久化Trie上,将复杂度降为$ n \log(4294967295)$,可以通过此题

然后还有一种维护类似于超级钢琴的做法,我并不了解

对于我改题的时候,写的是一个可持久化Trie+堆的做法,我们维护一个大根堆,将以$i$为结尾的区间中最大的推入堆

然后每次找到堆顶,查找对应右端点下一个比这个小一点的区间是多大,然后再推入堆即可

复杂度很显然,为:$(n+k)\log (4294967295)$

// luogu-judger-enable-o2
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <bitset>
using namespace std;
#define N 500005
#define ll long long
int n,K,now[N];unsigned a[N];long long ans;
struct Trie
{
int ch[N*33][2],siz[N*33],cnt,rot[N];
inline void copy(int x,int y){siz[x]=siz[y];ch[x][0]=ch[y][0];ch[x][1]=ch[y][1];}
inline void insert(unsigned x,int id)
{
int rt=++cnt,lst=rot[id-1],t;rot[id]=rt;copy(rt,lst);
for(int i=31;~i;i--)
{
t=(x>>i)&1;
ch[rt][t]=++cnt;rt=ch[rt][t];lst=ch[lst][t];
copy(rt,lst);siz[rt]++;
}
}
inline int query(unsigned x,int id,int K)
{
int rt=rot[id],t;unsigned ret=0;
for(int i=31;~i;i--)
{
if(!rt)return ret;t=(x>>i)&1;
if(K>siz[ch[rt][!t]])K-=siz[ch[rt][!t]],rt=ch[rt][t];
else rt=ch[rt][!t],ret|=1u<<i;
}
return ret;
}
}tr;
priority_queue<pair<unsigned ,int > >q;
int main()
{
// freopen("xor.in","r",stdin);
// freopen("xor.out","w",stdout);
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++)scanf("%u",&a[i]),a[i]^=a[i-1],tr.insert(a[i-1],i);
for(int i=1;i<=n;i++)q.push(make_pair(tr.query(a[i],i,++now[i]),i));int t;
while(K--)ans+=q.top().first,t=q.top().second,q.pop(),q.push(make_pair(tr.query(a[t],t,++now[t]),t));
printf("%lld\n",ans);
}

长度较短,是一个相对简单的可持久化数据结构套路

B

难度等级 3

可以转化为一个经典的字符串问题,可以容易的想到,使用字符串hash拿到$40$分的成绩

然后可以想到使用Sa,找到满足某个位置之后的字符串是这个B串的rank区间,然后使用线段树优化建图来完成,能拿到$80$分的优秀成绩,然后我就不太会了,并且代码量较高,并不能在很短的时间内完成

同时,可以想到使用Sam解决,在后缀树上主席树合并优化建图,然后再倍增定位节点同样可以拿到$80$分的优秀成绩,但是同样,代码复杂度较高

在此基础上,我们发现,线段树合并这步没有意义,直接在后缀树上拆点连边,后缀树优化建图,就可以拿到$80$分的优秀成绩

然后在此基础上,将每个节点的长度和编号按照长度从小到大,先b后a的顺序排序,然后前缀优化建图,即可拿到$100$分的优秀成绩

代码复杂度相对不高,整体考查了选手对于字符串经典模型的转化,前缀优化建图,后缀树的基本应用等知识,对字符串方面薄弱的选手是一个沉重的打击

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <bitset>
using namespace std;
#define ll long long
int n,na,nb,tot,cnt_SAM,oth,p[400005];char s[200005];
namespace Graph
{
const int N = 1000005;
struct node{int to,next;}e[N<<2];int head[N],cnt,in[N],q[N],a[N];ll f[N];
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;in[y]++;}
void init(){cnt=0;memset(head,-1,sizeof(int)*(tot+3));memset(in,0,sizeof(int)*(tot+3));memset(a,0,sizeof(int)*(tot+3));}
ll tsort()
{
int l=0,r=0;for(int i=1;i<=tot;i++)if(!in[i])q[r++]=i;
while(l<r)
{
int x=q[l++];
for(int i=head[x];i!=-1;i=e[i].next)
{
int to1=e[i].to;
if(!(--in[to1]))q[r++]=to1;
}
}
if(r!=tot)return -1;ll ans=0;
for(int j=r-1;~j;j--)
{
int x=q[j];f[x]=a[x];
for(int i=head[x];i!=-1;i=e[i].next)f[x]=max(f[x],f[e[i].to]+a[x]);
ans=max(ans,f[x]);
}return ans;
}
}
inline bool cmp(const pair<int ,int > &a,const pair<int ,int >&b){return a.first==b.first?a.second>b.second:a.first<b.first;}
// SAM
namespace Sam
{
const int N = 400005;
int trs[N][26],len[N],fa[N],pos[N],lst,cnt;vector<pair<int ,int > >s[N];
inline void init(){lst=cnt=1;memset(trs[1],0,sizeof(trs[1]));fa[1]=len[1]=0;}
inline int new_node(){cnt++;fa[cnt]=len[cnt]=0;memset(trs[cnt],0,sizeof(trs[cnt]));s[cnt].clear();return cnt;}
inline void insert(int x,int id)
{
int np=new_node(),nq,p=lst,q;len[np]=len[p]+1;pos[id]=np;lst=np;
for(;p&&!trs[p][x];p=fa[p])trs[p][x]=np;
if(!p)fa[np]=1;else if(len[q=trs[p][x]]==len[p]+1)fa[np]=q;
else
{
len[nq=new_node()]=len[p]+1;fa[nq]=fa[q];fa[q]=fa[np]=nq;
memcpy(trs[nq],trs[q],sizeof(trs[nq]));
for(;p&&trs[p][x]==q;p=fa[p])trs[p][x]=nq;
}
}
struct node{int to,next;}e[N];int head[N],edge_cnt;
inline void add(int x,int y){e[edge_cnt]=(node){y,head[x]};head[x]=edge_cnt++;}
int f[N][19];
void dfs(int x,int from)
{
f[x][0]=from;for(int i=1;i<19;i++)f[x][i]=f[f[x][i-1]][i-1];
for(int i=head[x];i!=-1;i=e[i].next)dfs(e[i].to,x);
}
inline void build(){cnt_SAM=cnt;memset(head,-1,sizeof(int)*(cnt+3));edge_cnt=0;for(int i=2;i<=cnt;i++)add(fa[i],i);dfs(1,0);}
inline void query(int l,int p,int id)
{
int x=pos[p];
for(int i=18;~i;i--)if(len[f[x][i]]>=l)x=f[x][i];
s[x].push_back(make_pair(l,id));
}
inline void build_Graph()
{
oth=0;
for(int i=2;i<=cnt;i++)
{
sort(s[i].begin(),s[i].end(),cmp);int lim=s[i].size(),lst=i;
for(int j=0;j<lim;j++)
{
int x=s[i][j].second+cnt;p[s[i][j].second]=x;
if(j==0)Graph::add(i,x);else Graph::add(s[i][j-1].second+cnt,x);
lst=x;
if(s[i][j].second<=na)
{
int u=na+nb+cnt+(++oth);
p[s[i][j].second]=u;Graph::add(x,u);
Graph::a[u]=s[i][j].first;
}
}
for(int j=head[i];j!=-1;j=e[j].next)Graph::add(lst,e[j].to);
}
}
}
int T,Case;
void solve()
{
scanf("%s",s+1);n=strlen(s+1);Sam::init();
for(int i=n;i;i--)Sam::insert(s[i]-'a',i);Sam::build();scanf("%d",&na);
for(int i=1,l,r;i<=na;i++)scanf("%d%d",&l,&r),Sam::query(r-l+1,l,i);scanf("%d",&nb);
for(int i=1,l,r;i<=nb;i++)scanf("%d%d",&l,&r),Sam::query(r-l+1,l,i+na);
tot=(cnt_SAM)+(na<<1)+nb;Graph::init();Sam::build_Graph();
int m;scanf("%d",&m);for(int x,y;m--;Graph::add(p[x],p[y+na]))scanf("%d%d",&x,&y);
printf("%lld\n",Graph::tsort());
}
int main(){scanf("%d",&T);while(T--)Case++,solve();}

可以显然的发现,我就是那个被打击的

C

难度等级 5

这个题不太能做吧?

1_998244353直接费马小定理+快速幂就可以了

1?暴力找一个模数即可,模数为$1145141$

1?+通过找到输入数据中,输入最接近的两个数,找到对应答案里的位置,然后通过观察输出数据找到模数的大致区间,然后验证即可,模数为$5211600617818708273$

1wa_998244353,观察可以发现,这个是在乘法的过程中爆$int$了,然后第一个可以直接暴力每次乘以$19$,第二个的话,一种是可以分块打表,也可以通过找循环节搞定

2p的话,就是如果是质数,该位为$p$否则为$.$,然后8是直接线筛,9是线筛+根号求,10是$Miller-Rabin$

2u的话,就是莫比乌斯函数,前两个类似上面的前两个,最后一个打表+线筛即可

2g的话,就是原根,我不会

没写

D

难度等级 4

可以说是一个非常好的高维DP问题,数据范围具有迷惑性,让人觉得暴力能过,然后本人尝试卡常,然后失败了,最后只拿到了$50$分

我们先给出一个DP方程:$f[i][j][k][0/1]$表示前$i$个学校,蓝阵营有$j$个人,鸭派系有$k$个人的方案数,然后每次直接转移即可,特判不多,属于可以接受的范围

然后我们发现$k$比较小,所以我们考虑提出一个复杂度阈值有关$k$的做法

那么我们先从$k=0$入手

对于$k=0$的情况,我们发现,不论这个城市选择哪一个阵营,如何选择,和学校选择哪个派系没有任何关系

因为对于每个阵营,都有两个派系可以选,并且因为$k=0$所以具体选哪个阵营没啥意义

所以答案即为$选择派系的分组数\times 选择阵营的分组数$,这两个东西分别DP一下即可

然后我们考虑$k \neq 0$的情况,可以发现,一定最多只有$k$个城市和$k$个学校不会被访问

这样我们发现可以单独对这$k$个城市DP,然后剩下的的东西做一遍$k=0$的情况即可

但是我们发现,这样如果这$k$个城市的学校数=n的话,那复杂度就依然为$nm^2$就没有发生任何优化

那么我们考虑将这个问题和$k=0$结合起来

我们发现,对于这样的对于存在约束的学校,只需要正常DP一下,然后对于没有约束的学校,你只需钦定它的阵营,并不需要钦定它的派系,派系只需要最后搞一下就可以了

然后这样的话,就可以做到:$O(km^2 + n\times m)$解决了

可能会被卡常,然后稍微优化一下复杂度上届即可

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <bitset>
using namespace std;
#define N 2505
#define ll long long
#define mod 998244353
int f[N][305],g[N][305],f1[N],f0[N];
int n,c,k,C0,C1,D0,D1,M,S,bel[N],sz[N],hat[N],ht[N],s[N];
void get_f0()
{
f0[0]=1;
for(int i=1;i<=n;i++)if(hat[i]==-1)
for(int j=M;j>=sz[i];j--)f0[j]=(f0[j]+f0[j-sz[i]])%mod;
for(int j=1;j<=M;j++)(f0[j]+=f0[j-1])%=mod;
}
void get_f1()
{
f1[0]=1;
for(int i=1;i<=c;i++)if(s[i]&&ht[i]==-1)
for(int j=M;j>=s[i];j--)f1[j]=(f1[j]+f1[j-s[i]])%mod;
for(int j=1;j<=M;j++)(f1[j]+=f1[j-1])%=mod;
}
inline int get(int v0,int v1)
{
int l0=max(C0-v0,0),r0=min(C1-v0,M),l1=max(D0-v1,0),r1=min(D1-v1,M);
if(l0>r0||l1>r1)return 0;return (ll)(f1[r0]-(l0?f1[l0-1]:0))*(f0[r1]-(l1?f0[l1-1]:0))%mod;
}
void solve()
{
memset(f,0,sizeof(f));memset(g,0,sizeof(g));memset(hat,-1,sizeof(hat));S=0;
memset(ht,-1,sizeof(ht));memset(f1,0,sizeof(f1));memset(f0,0,sizeof(f0));memset(s,0,sizeof(s));
scanf("%d%d%d%d%d%d",&n,&c,&C0,&C1,&D0,&D1);M=max(max(C0,C1),max(D0,D1));
for(int i=1;i<=n;i++)scanf("%d%d",&bel[i],&sz[i]),s[bel[i]]+=sz[i],S+=sz[i];
scanf("%d",&k);for(int i=1,x,y;i<=k;i++)scanf("%d%d",&x,&y),ht[bel[x]]=hat[x]=y;
get_f0();get_f1();C1=max(S-C1,0),D1=max(S-D1,0);swap(C0,C1);swap(D0,D1);
if(C0>C1||D0>D1)return puts("0"),void();g[0][0]=1;int S0=0,S1=0;
for(int i=1;i<=c;i++)if(ht[i]!=-1)
{
for(int j=S0;~j;j--)for(int k=S1;~k;k--)f[j][k]=g[j][k];
for(int j=1;j<=n;j++)if(bel[j]==i&&hat[j]!=-1)
{
S1+=sz[j];
if(hat[j]==1)for(int k=S0;~k;k--){for(int l=S1;l>=sz[j];l--)g[k][l]=g[k][l-sz[j]];for(int l=0;l<sz[j];l++)g[k][l]=0;}
else if(hat[j]!=0)for(int k=S0;~k;k--)for(int l=S1;l>=sz[j];l--)g[k][l]=(g[k][l]+g[k][l-sz[j]])%mod;
if(hat[j]==3)for(int k=S0;~k;k--){for(int l=S1;l>=sz[j];l--)f[k][l]=f[k][l-sz[j]];for(int l=0;l<sz[j];l++)f[k][l]=0;}
else if(hat[j]!=2)for(int k=S0;~k;k--)for(int l=S1;l>=sz[j];l--)f[k][l]=(f[k][l]+f[k][l-sz[j]])%mod;
}
S0+=s[i];S0=min(S0,M);
for(int j=S0;~j;j--)for(int k=S1;~k;k--)g[j][k]=((j>=s[i]?g[j-s[i]][k]:0)+f[j][k])%mod;
}
int ans=0;
for(int i=0;i<=S0;i++)for(int j=0;j<=S1;j++)ans=(ans+(ll)g[i][j]*get(i,j))%mod;
printf("%d\n",(ans+mod)%mod);
}
int main(){int T;scanf("%d",&T);while(T--)solve();}

E

难度评级 2

一道不失幽默的树上贪心数据结构问题

其实看一看就能发现,对每个子树,按照从大到小排序后,按位置合并即可

这样就能拿到$60$分的优秀成绩了

然后正解就是上述算法优化一下即可

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <bitset>
#include <set>
using namespace std;
#define N 200005
#define ll long long
multiset<int ,greater<int > >s[N];
vector<int >v;
struct node{int to,next;}e[N];int head[N],cnt,a[N],n,idx[N];
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;}
void merge(int x,int y)
{
if(s[x].size()<s[y].size())swap(s[x],s[y]);
for(;s[y].size();s[x].erase(s[x].begin()),s[y].erase(s[y].begin()))
v.push_back(max(*s[x].begin(),*s[y].begin()));
for(int i=0;i<v.size();i++)s[x].insert(v[i]);
v.clear();
}
void dfs(int x)
{
for(int i=head[x];i!=-1;i=e[i].next)
dfs(e[i].to),merge(x,e[i].to);
s[x].insert(a[x]);
}
int main()
{
scanf("%d",&n);memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=2,x;i<=n;i++)scanf("%d",&x),add(x,i);
dfs(1);long long ans=0;
while(s[1].size())ans+=*s[1].begin(),s[1].erase(s[1].begin());
printf("%lld\n",ans);
}

F

不会,滚

十二省联考题解 - JLOI2019 题解的更多相关文章

  1. 「ZJOI2019」&「十二省联考 2019」题解索引

    「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...

  2. P5290 [十二省联考2019]春节十二响

    题目地址:P5290 [十二省联考2019]春节十二响 骗分方法 如果你实在一点思路也没有,暴力都不会打,那么请考虑一下骗分. 方法一 输出所有 \(M\) 的和. 期望得分:0分. 实际还有5分 方 ...

  3. 十二省联考 - JLOI2019 游记

    十二省联考 - JLOI 2019 游记 想了想,还是起一个副标题吧 一场失败的胜利 Day -inf 想了想,还是从头开始说吧. 其实考完NOIP之后,大概估算一下,吉林省队的数量还算是比较乐观的, ...

  4. 【简】题解 P5283 [十二省联考2019]异或粽子

    传送门:P5283 [十二省联考2019]异或粽子 题目大意: 给一个长度为n的数列,找到异或和为前k大的区间,并求出这些区间的异或和的代数和. QWQ: 考试时想到了前缀异或 想到了对每个数按二进制 ...

  5. CQOI2019(十二省联考)游记

    CQOI2019(十二省联考)游记 Day -? 自从联赛爆炸,\(THUWC\)爆炸,\(WC\)爆炸(就没有不爆炸的)之后我已经无所畏惧... 听说是考\(4.5 h\)吗? Day -1 \(Z ...

  6. 【BZOJ5495】[十二省联考2019]异或粽子(主席树,贪心)

    [BZOJ5495][十二省联考2019]异或粽子(主席树,贪心) 题面 BZOJ 洛谷 题解 这不是送分题吗... 转异或前缀和,构建可持久化\(Trie\). 然后拿一个堆维护每次的最大值,每次如 ...

  7. 【BZOJ5496】[十二省联考2019]字符串问题(后缀树)

    [BZOJ5496][十二省联考2019]字符串问题(后缀树) 题面 BZOJ 洛谷 题解 首先显然可以把具有支配关系的串从\(A\)到\(B\)连一条有向边,如果\(B_i\)是\(A_j\)的前缀 ...

  8. 【BZOJ5498】[十二省联考2019]皮配(动态规划)

    [BZOJ5498][十二省联考2019]皮配(动态规划) 题面 BZOJ 洛谷 题解 先考虑暴力\(dp\),设\(f[i][j][k]\)表示前\(i\)所学校,有\(j\)人在某个阵营,有\(k ...

  9. [十二省联考2019]异或粽子 01trie

    [十二省联考2019]异或粽子 01trie 链接 luogu 思路 首先求前k大的(xo[i]^xo[j])(i<j). 考场上只想到01trie,不怎么会写可持久,就写了n个01trie,和 ...

随机推荐

  1. mac 苹果多版本jdk自由切换

    场景 手头上的工具有时候依赖低版本jdk,有时候需要高版本jdk, 如何在不同版本jdk之间来回自由的切换? 安装 首选需要去官网下载dmg安装包,地址:https://www.oracle.com/ ...

  2. 关于一体机打印新加菜按钮更改为下单小票打印设置FAQ(适用正餐6.0.1.0+,轻餐4.0.6.2+)

    适用版本:正餐6.0.1.0+,轻餐4.0.6.2+ 实际场景:更新后小票设置中的打印新加菜按钮更换为下单小票打印设置,更换后,设置中,有3个选项: 1.仅打印新加菜    (选中后,订单加菜后前台小 ...

  3. SQL Server等待事件—RESOURCE_SEMAPHORE_QUERY_COMPILE

    等待事件介绍 关于等待事件RESOURCE_SEMAPHORE_QUERY_COMPILE,官方的介绍如下: Occurs when the number of concurrent query co ...

  4. 图文并茂 RAID 技术全解 – RAID0、RAID1、RAID5、RAID10

    RAID 技术相信大家都有接触过,尤其是服务器运维人员,RAID 概念很多,有时候会概念混淆.这篇文章为网络转载,写得相当不错,它对 RAID 技术的概念特征.基本原理.关键技术.各种等级和发展现状进 ...

  5. ASP.NET MVC从视图传参到控制器的几种形式

    1. 传递数组 $(function () { var value = ["C#", "JAVA", "PHP"]; $("inp ...

  6. Ubuntu下使用QQ/Wechat

    实验环境:Ubuntu 16.04桌面版root用户下 安装Docker 配置Docker的apt源 $ sudo apt-get install apt-transport-https ca-cer ...

  7. Visio画图--我的形状

    本人用的Visio 2013 打开Visio后新建一个拓扑图,发现左侧形状一栏不见了 形状栏可以保存很多自定义图形,怎么才能将形状一栏重新显示出来呢?方法其实很简单,方法如下所示: 这时候我们就会发现 ...

  8. June 11. 2018 Week 24th, Monday

    Love is the beauty of the soul. 爱是灵魂之美. From Saint Augustine. The complete version of this quote goe ...

  9. Mybatis 报错 There is no getter for property named '***' in 'class java.lang.String'

    在mapper.xml中 , 如果单参数是String类型 , 且在sql语句中对参数进行了判断 , 如下 when 中的判断 , 如果出现 if 判断也是一样的.都需要把判断中的参数用 _param ...

  10. (转)Spring Boot 2 (二):Spring Boot 2 尝鲜-动态 Banner

    http://www.ityouknow.com/springboot/2018/03/03/spring-boot-banner.html Spring Boot 2.0 提供了很多新特性,其中就有 ...