BJOI2019 题解


在更了在更了

P5319 [BJOI2019]奥术神杖

对\(V_i\)求个\(\ln\)变成了让平均数最大,显然套分数规划,然后ac自动机上面dp

#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il ll gi(){
ll x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
char T[1510],S[1510];
int ch[1510][10],trans[1510][10],fail[1510],cnt;
double W[1510];int sum[1510];
il vd insert(double d){
int n=strlen(S+1);
int x=0;
for(int i=1;i<=n;++i){
S[i]-='0';
if(!ch[x][S[i]])ch[x][S[i]]=++cnt;
x=ch[x][S[i]];
}
W[x]+=d;++sum[x];
}
int que[1510],hd,tl;
double f[1510][1510];
int g[1510][1510];
char h[1510][1510];
template<class T> il vd chkmx(T&a,T b){if(b>a)a=b;}
int main(){
#ifdef XZZSB
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
int n=gi(),m=gi();
scanf("%s",T+1);
for(int i=1;i<=m;++i)scanf("%s",S+1),insert(log(gi()));
for(int i=0;i<10;++i)if(ch[0][i])trans[0][i]=ch[0][i],que[tl++]=ch[0][i];
while(hd^tl){
int x=que[hd++];
for(int i=0;i<10;++i)
if(ch[x][i]){
int f=fail[x];
while(f&&!ch[f][i])f=fail[f];
fail[ch[x][i]]=ch[f][i];
que[tl++]=ch[x][i];
W[ch[x][i]]+=W[ch[f][i]];
sum[ch[x][i]]+=sum[ch[f][i]];
trans[x][i]=ch[x][i];
}else trans[x][i]=trans[fail[x]][i];
}
double l=0,r=1e9,mid;
while(r-l>1e-4){
mid=(l+r)*0.5;
for(int i=0;i<=cnt;++i)f[0][i]=-1e18;
f[0][0]=0;
for(int i=0;i<n;++i){
for(int j=0;j<=cnt;++j)f[i+1][j]=-1e18;
for(int j=0;j<=cnt;++j){
if(f[i][j]<-1e17)continue;
for(int k=0;k<10;++k)if(T[i+1]=='.'||k+'0'==T[i+1])chkmx(f[i+1][trans[j][k]],f[i][j]+W[trans[j][k]]-mid*sum[trans[j][k]]);
}
}
bool flg=0;
for(int i=0;i<=cnt;++i)if(f[n][i]>1e-7)flg=1;
if(flg)l=mid;
else r=mid;
}
for(int i=0;i<=cnt;++i)f[0][i]=-1e18;
f[0][0]=0;
for(int i=0;i<n;++i){
for(int j=0;j<=cnt;++j)f[i+1][j]=-1e18;
for(int j=0;j<=cnt;++j){
if(f[i][j]<-1e17)continue;
for(int k=0;k<10;++k)
if(T[i+1]=='.'||k+'0'==T[i+1])
if(f[i+1][trans[j][k]]<f[i][j]+W[trans[j][k]]-l*sum[trans[j][k]]){
f[i+1][trans[j][k]]=f[i][j]+W[trans[j][k]]-l*sum[trans[j][k]];
g[i+1][trans[j][k]]=j;
h[i+1][trans[j][k]]='0'+k;
}
}
}
double F=1e-18;int G=0;
for(int i=0;i<=cnt;++i)if(f[n][i]>F)F=f[n][i],G=i;
for(int i=n;i;--i)T[i]=h[i][G],G=g[i][G];
printf("%s",T+1);
return 0;
}

P5320 [BJOI2019]勘破神机

神鸡???

这是一个强行二合一,但这两个题还是有关系的

先看\(ans2\) 化一下式子就可以知道答案和\(\sum_{i=0}^n\binom{fib_i}k\)有关。

再看看\(ans3\),显然\(n\)为奇数是没有答案,设\(f_n\)表示\(2n\)列时的答案。

考虑怎么放。首先有一种放法就是三个横条,从\(f_{n-1}\)转移过来,1种放法;还有一种方法就是

---------
| | | |
- ----- -
| | | |
---------
| | |
---------

这样可以放任意长度为偶数的段,而且上下翻转也是一种方案,所以从任意的\(f_{i}(i<n)\)可以转移过来,有2种方法。

综上,\(f_n=f_{n-1}+2\sum_{i=0}^{n-1}f_i\)

设\(g_n=\sum_{i=0}^nf_n\),那么用上面的递推式改改可以得到另一个递推式\(g_n=4g_{n-1}-g_{n-2}\)。

下面\(ans2\)和\(ans3\)的方法是类似的。

\(\binom nk\)显然是个\(k\)次多项式,可以\(O(k^2)\)的时间预处理出来

那么答案变成了

\(\sum_{i=0}^n\sum_{j=0}^ka_jfib_i^j\)

\(\sum_{j=0}^ka_j\sum_{i=0}^nfib_i^j\)

那么问题变成了对每一个\(k\)计算\(\sum_{i=0}^nfib_i^k\)

考虑\(fib\)的通项公式,我们知道了是\(f(n)=\frac{(\frac{1+\sqrt5}2)^n-(\frac{1-\sqrt5}2)^n}{\sqrt5}\)。

再看看\(ans3\)的通项公式,可以解出来\(f(n)=\frac{(3+\sqrt3)(2+\sqrt3)^n+(3-\sqrt3)(2-\sqrt3)^n}{6}\)

统一写成\(f(x)=ab^i+cd^i\)。

\(\sum_{i=0}^n(ab^i+cd^i)^k\)

用二项式定理直接展开,\(\sum_{i=0}^n\sum_{j=0}^k\binom kj (ab^i)^j(cd^i)^{k-j}\)

\(\sum_{i=0}^n\sum_{j=0}^k\binom kj a^jb^{ij}c^{k-j}d^{i(k-j)}\)

\(\sum_{i=0}^nf(i)^k=\sum_{j=0}^k\binom kj a^jc^{k-j}\sum_{i=0}^n(b^{j}d^{k-j})^i\)

后面直接等比数列求和即可,那么这个式子就能算了。

但是需要注意, \(3\)和\(5\)在\(\mod 998244353\)意义下都没有二次剩余,可以开一个struct存\(a,b\),真实数就是\(a+b\sqrt 5\)。

推\(F_x\)通项的方法:不想写了,贴个链接https://blog.csdn.net/liuzibujian/article/details/82595918

#include<bits/stdc++.h>
#define il inline
#define vd void
#define mod 998244353
#define ll long long
il ll gi(){
ll x=0,f=0;char ch=getchar();
while(!isdigit(ch))f^=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
il int pow(int a,int b){
int ret=1;
while(b){
if(b&1)ret=1ll*ret*a%mod;
a=1ll*a*a%mod;b>>=1;
}
return ret;
}
ll k,l,r,qt,m;
struct number{
int a,b;
number inv()const{
int fm=pow((1ll*a*a-qt*b*b%mod+mod)%mod,mod-2);
return (number){1ll*a*fm%mod,(mod-1ll*b*fm%mod)%mod};
}
};//a+b*sqrt(qt)
il number getnum(int x){return(number){x,0};}
il number operator+(const number&a,const number&b){return(number){(a.a+b.a)%mod,(a.b+b.b)%mod};}
il number operator-(const number&a,const number&b){return(number){(a.a-b.a+mod)%mod,(a.b-b.b+mod)%mod};}
il number operator*(const number&a,const number&b){return(number){(1ll*a.a*b.a+qt*a.b*b.b)%mod,(1ll*a.a*b.b+1ll*a.b*b.a)%mod};}
il number operator/(const number&a,const number&b){return a*b.inv();}
il number Pow(number a,ll b){
number ret=getnum(1);
while(b){
if(b&1)ret=ret*a;
a=a*a;b>>=1;
}
return ret;
}
int A[510],B[510],C[510][510];
number pa[510],pb[510],pc[510],pd[510];
il ll solve(ll n){
ll ans=0;
for(int i=0;i<=k;++i){
ll res=0;
for(int o=0;o<=i;++o){
number _res=getnum(C[i][o]);
number p=pb[o]*pd[i-o];
if(p.a==1&&p.b==0)_res=_res*getnum(n%mod);
else _res=_res*(Pow(p,n+1)-getnum(1))/(p-getnum(1));
res=(res+(_res*pa[o]*pc[i-o]).a)%mod;
}
ans=(ans+res*A[i])%mod;
}
return ans;
}
il vd init(){
if(m==2)qt=5;
else qt=3;
C[0][0]=1;
for(int i=1;i<=501;++i){
C[i][0]=1;
for(int j=1;j<=i;++j)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
pa[0]=pb[0]=pc[0]=pd[0]=getnum(1);
if(m==2){
pa[1]=(number){1,0}/(number){0,1};
pb[1]=(number){1,1}/getnum(2);
pc[1]=(number){mod-1,0}/(number){0,1};
pd[1]=(number){1,mod-1}/getnum(2);
}else{
pa[1]=(number){3,1}/getnum(6);
pb[1]=(number){2,1};
pc[1]=(number){3,mod-1}/getnum(6);
pd[1]=(number){2,mod-1};
}
for(int i=2;i<=501;++i)pa[i]=pa[i-1]*pa[1],pb[i]=pb[i-1]*pb[1],pc[i]=pc[i-1]*pc[1],pd[i]=pd[i-1]*pd[1];
}
il vd work(){
memset(A,0,sizeof A);A[0]=1;
for(int i=0;i<k;++i){
memcpy(B,A,sizeof A);
memset(A,0,sizeof A);
for(int j=0;j<=k;++j)A[j]=mod-1ll*B[j]*i%mod;
for(int j=0;j<=k;++j)A[j+1]=(A[j+1]+B[j])%mod;
}
ll _l,_r;
if(m==3)_l=(l+1)/2-1,_r=r/2-1;
else _l=l,_r=r;
ll ans=(solve(_r+1)-solve(_l)+mod)%mod;
for(int i=1;i<=k;++i)ans=ans*pow(i,mod-2)%mod;
printf("%lld\n",ans*pow((r-l+1)%mod,mod-2)%mod);
}
int main(){
#ifdef XZZSB
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
int T=gi();m=gi();
init();
while(T--){
l=gi(),r=gi(),k=gi();
work();
}
return 0;
}

P5321 [BJOI2019]送别

等zsy更了我再更。

P5322 [BJOI2019] 排兵布阵

直接dp。

#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il ll gi(){
ll x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
int f[101][20001],a[101][101];
int main(){
#ifdef XZZSB
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
int s=gi(),n=gi(),m=gi();
for(int i=1;i<=s;++i)
for(int j=1;j<=n;++j)
a[j][i]=gi()*2+1;
for(int i=1;i<=n;++i){
std::sort(a[i]+1,a[i]+s+1);
for(int j=0;j<=m;++j)
for(int k=0;k<=s;++k)
if(j+a[i][k]<=m)f[i][j+a[i][k]]=std::max(f[i][j+a[i][k]],f[i-1][j]+i*k);
else break;
}
printf("%d\n",f[n][m]);
return 0;
}

P5323 [BJOI2019] 光线

几块玻璃可以合起来,这块玻璃有从上到下/从下到上的透光度/反射度。

每次合并\(1-i\)的玻璃和\(i+1\)玻璃,发现上面这个玻璃只要记上到下的透光度和下到上的反射度就行了。

新玻璃透光度和反射度的式子手推就行了,大约是一个等比数列。

#include<bits/stdc++.h>
#define il inline
#define vd void
#define mod 1000000007
typedef long long ll;
il ll gi(){
ll x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
il vd exgcd(int a,int b,int&x,int&y){
if(!b)x=1,y=0;
else exgcd(b,a%b,y,x),y-=x*(a/b);
}
il int inv(int o){
int a=o,b=mod,x,y;
exgcd(a,b,x,y);
return (x+mod)%mod;
}
int main(){
#ifdef XZZSB
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
int n=gi();
int a1=gi()*570000004ll%mod,b1=gi()*570000004ll%mod;
for(int i=2;i<=n;++i){
int a2=gi()*570000004ll%mod,b2=gi()*570000004ll%mod;
int iv=inv((mod+1-1ll*b1*b2%mod)%mod);
int a3=1ll*a1*a2%mod*iv%mod;
int b3=(b2+1ll*a2*a2%mod*b1%mod*iv%mod)%mod;
a1=a3,b1=b3;
}
printf("%d\n",a1);
return 0;
}

P5324 [BJOI2019] 删数

有一个简单的dp,\(f[i]\)表示现在长度为\(i\),每次删\(j\)个\(i\)并跳到\(i-j\),如果没有一个\(i\)直接跳到\(i-1\),这样跳到\(0\)最多删掉多少数。

然后有一个差不多的问题:设数\(i\)有\(cnt_i\)个,就覆盖\([i-cnt_i+1,i]\),求最后多少个数没有被覆盖。感性理解感性证明这个的答案和上面的\(dp\)一样。

那么就是一个普及题了:用线段树维护,每次修改两个\(cnt\)或者移动区间(都可以变成区间加),查询线段树上一段\(0\)的数量。移动区间可以线段树两边都扩展\(m\)。

查询线段树上一段\(0\)的数量,我以为要记是0的数量,就做不了了。实际上不会有数减到\(-1\),所以可以记最小值的数量,就能做了。

#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il int gi(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch))f^=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,m,N,L,a[450002],cnt[450002];
#define mid ((l+r)>>1)
int lz[1800010];
std::pair<int,int>s[1800010];
il std::pair<int,int>operator+(std::pair<int,int>a,std::pair<int,int>b){
if(a.first<b.first)return a;
else if(a.first>b.first)return b;
else return{a.first,a.second+b.second};
}
il vd build(int x,int l,int r){
s[x].second=r-l+1;if(l==r)return;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
}
il vd upd(int x,int y){s[x].first+=y;lz[x]+=y;}
il vd down(int x){if(lz[x])upd(x<<1,lz[x]),upd(x<<1|1,lz[x]),lz[x]=0;}
il vd update(int x,int l,int r,const int&L,const int&R,const int&d){
if(L<=l&&r<=R)return upd(x,d);
down(x);
if(L<=mid)update(x<<1,l,mid,L,R,d);
if(mid<R)update(x<<1|1,mid+1,r,L,R,d);
s[x]=s[x<<1]+s[x<<1|1];
}
il std::pair<int,int>query(int x,int l,int r,const int&L,const int&R){
if(L<=l&&r<=R)return s[x];
down(x);
if(L<=mid)
if(mid<R)return query(x<<1,l,mid,L,R)+query(x<<1|1,mid+1,r,L,R);
else return query(x<<1,l,mid,L,R);
else return query(x<<1|1,mid+1,r,L,R);
}
il vd update(int p,int x){
if(x==1){
if(1<=p-cnt[p]&&p-cnt[p]<=N&&L+1<=p&&p<=L+n)update(1,1,N,p-cnt[p],p-cnt[p],1);
++cnt[p];
}else{
if(1<=p-cnt[p]+1&&p-cnt[p]+1<=N&&L+1<=p&&p<=L+n)update(1,1,N,p-cnt[p]+1,p-cnt[p]+1,-1);
--cnt[p];
}
}
#undef mid
int main(){
n=gi(),m=gi(),N=n+m*2+2,L=m+1;
int p,x;
build(1,1,N);
for(int i=1;i<=n;++i)update(a[i]=gi()+L,1);
for(int i=1;i<=m;++i){
p=gi(),x=gi();
if(p>0)update(a[p],-1),update(a[p]=x+L,1);
else
if(x==1)update(1,1,N,L+n-cnt[L+n]+1,L+n,-1),--L,update(1,1,N,L+1-cnt[L+1]+1,L+1,1);
else update(1,1,N,L+1-cnt[L+1]+1,L+1,-1),++L,update(1,1,N,L+n-cnt[L+n]+1,L+n,1);
auto ans=query(1,1,N,L+1,L+n);
printf("%d\n",ans.first?0:ans.second);
}
return 0;
}

BJOI2019 题解的更多相关文章

  1. 题解-BJOI2019 光线

    Problem loj3093 & x谷 题意概要:给定 \(n\) 块玻璃,每块玻璃有其折射比例与反射比例(折射比例+反射比例 不一定为 \(100\%\)),求从最上头打下一束光,有多少比 ...

  2. 可能是 BJOI2019 Day1 题解?

    T1 给一个有空白字符的串 $S$,和若干模板串 $X_i$,初始 $Ans = 1$,每当一个模板串在 $S$ 中作为子串出现时,$Ans$ 会乘以 $X_i$ 的权值 $Val_i$,然后如果 $ ...

  3. 【题解】Luogu P5319 [BJOI2019]奥术神杖

    原题传送门 题目让我们最大化\(val=\sqrt[k]{\prod_{i=1}^k w_i}\),其中\(k\)是咒语的个数,\(w_i\)是第\(i\)个咒语的神力 看着根号和累乘不爽,我们两边同 ...

  4. 【题解】Luogu P5324 [BJOI2019]删数

    原题传送门 易知这个数列的顺序是不用考虑的 我们看两个数列 \(1,2,3\)和\(3,3,3\)都能删完,再看两个数列\(1,2,3,4\)和\(2,2,4,4\),也都能删完 不难发现,我们珂以把 ...

  5. 题解 洛谷 P5324 【[BJOI2019]删数】

    先考虑对于一个序列,能使其可以删空的的修改次数. 首先可以发现,序列的排列顺序是没有影响的,所以可以将所有数放到桶里来处理. 尝试对一个没有经过修改的可以删空的序列来进行删数,一开始删去所有的\(n\ ...

  6. 题解 [BJOI2019]奥术神杖

    题目传送门 题目大意 给出一个残缺的字符串,每个位置都 \(\in[0,9]\).有 \(m\) 中贡献,即 \(s,k\),表示该字符串中没出现一次 \(s\),贡献便乘上 \(k\).最后对贡献求 ...

  7. 题解 P5320 - [BJOI2019]勘破神机(推式子+第一类斯特林数)

    洛谷题面传送门 神仙题(为什么就没能自己想出来呢/zk/zk) 这是我 AC 的第 \(2\times 10^3\) 道题哦 首先考虑 \(m=2\) 的情况,我们首先可以想到一个非常 trivial ...

  8. [BJOI2019]删数(线段树)

    [BJOI2019]删数(线段树) 题面 洛谷 题解 按照值域我们把每个数的出现次数画成一根根的柱子,然后把柱子向左推导,\([1,n]\)中未被覆盖的区间长度就是答案. 于是问题变成了单点修改值,即 ...

  9. [BJOI2019]光线(递推)

    [BJOI2019]光线(递推) 题面 洛谷 题解 假装玻璃可以合并,假设前面若干玻璃的透光率是\(A\),从最底下射进去的反光率是\(B\),当前的玻璃的透光率和反光率是\(a,b\). 那么可以得 ...

随机推荐

  1. JMeter—断言(十一)

    参考<全栈性能测试修炼宝典JMeter实战>第六章 JMeter 元件详解中第六节断言断言用来对服务器的响应数据做验证,常用的断言是响应断言,支持正则表达式. 一.BeanShell As ...

  2. ffmpeg文件切片

    先用ffmpeg把abc.mp4文件转换为abc.ts文件: ffmpeg -y -i abc.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb ...

  3. [cb]SceneView 获取鼠标位置

    扩展需求 在Scene视图中获取鼠标的位置 Demo 在Scene视图中,当鼠标点击时实例化一个Cube 重点部分 实现代码 using UnityEngine; using UnityEditor; ...

  4. dell t130服务器安装windowsserver2008R2系统

    dell T130服务器系统是可以安装windowsserver2008R2系统. 总共8个USB端口: 后置USB:2个USB 3.0和4个USB 2.0 前置USB:1个USB 2.0和1个USB ...

  5. 薛兆丰吴军何帆曾鸣万维刚李笑来罗永浩等得到APP专栏作者的书23本

    最近看了何帆的<大局观>,是他在得到APP的专栏文章的精选.顺便整理以下最近两三年内看过的得到APP其他专栏与课程作者的得到精选文集和他们写过的其他的书共23本. 薛兆丰 4星|<薛 ...

  6. Reveal安装

    一.安装 第一步:将Reveal.framework拖入工程中(下载地址:http://pan.baidu.com/s/1mgMJVDI,解压后产生的Reveal.framework,拖入工程即可). ...

  7. Linux 下安装Node.js

    安装 node.js 安装包 http://nodejs.org 通过 rz 上传到 CentOS 进行解压 tar -xvf node-v8.0.0-linux-x64.tar.xz 进入到 bin ...

  8. robotframework接口测试(一)—Get request json

    (前提:引入了 requests.requestsLibrary等相关库,这样才可以只有相关的关键字.) 理想中的过程: 1. 创建session 2. 在该session下发起请求 3. 验证返回结 ...

  9. slf4j+logback搭建超实用的日志管理模块

    文章转自http://www.2cto.com/kf/201702/536097.html slf4j+logback搭建超实用的日志管理模块(对日志有编号管理):日志功能在服务器端再常见不过了,我们 ...

  10. mysql索引类型-方法-形式-使用时机-不足之处--注意事项

    一.索引的类型 1.普通索引   增加 create  index  index_name on table(colume(length));                       例子:cre ...