Codeforces 873 简要题解
A题
传送门
题意:
一个人要做nnn件事,时间花费分别为a1,a2,...,an,a1≤a2≤a3≤...≤ana_1,a_2,...,a_n,a_1\le a_2\le a_3\le...\le a_na1,a2,...,an,a1≤a2≤a3≤...≤an
现在可以把至多kkk件事分别花xxx时间做完,问做完的最小总花费。
思路:按照题意模拟
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=205;
int n,k,x,a[N];
int main(){
n=read(),k=read(),x=read();
for(ri i=1;i<=n;++i)a[i]=read();
int ans=0;
int pos=n-k;
for(ri i=n,cnt=1;i&&cnt<=k;--i,++cnt){
if(a[i]<=x){pos=i;break;}
ans+=x;
}
while(pos)ans+=a[pos--];
cout<<ans;
return 0;
}
B题
题意:
给一个长度为nnn的010101串,问其最长的长度为偶数子串的010101数相等的长度。
思路:
设000对应权值为−1-1−1,111对应权值为111,这样转化成求权值为000的长度为偶数的子区间数。
这个可以用前缀和来看,如果前缀和相等说明中间夹的一段合法。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
return getchar();
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=1e5+5;
char s[N];
int n,a[N];
int pos[N<<1][2];
int main(){
n=read();
scanf("%s",s+1);
memset(pos,-1,sizeof(pos));
pos[100000][0]=0;
int ans=0;
for(ri sum=0,i=1;i<=n;++i){
sum+=s[i]=='0'?-1:1;
if(~pos[sum+100000][i&1])ans=max(ans,i-pos[sum+100000][i&1]);
else pos[sum+100000][i&1]=i;
}
cout<<ans;
return 0;
}
C题
传送门
题意:给一个n∗mn*mn∗m的010101矩阵和一个数kkk,现在对每一列以如下方式计算贡献:
- 若这一列没有111,直接跳过。
- 如果有111,找到最靠上的一个111,然后贡献为从它开始向下连续至多kkk个格子中111的数量。
现在允许你把一些111变成000,问最后获得的贡献的最大值已经要使得贡献最大需要删掉格子的最小数量。
思路:对于每一列处理一个前缀和然后随便更新一下答案。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=105;
int n,m,k,a[N][N],sum[N][N],f[N][N];
int main(){
n=read(),m=read(),k=read();
for(ri i=1;i<=n;++i){
for(ri j=1;j<=m;++j){
a[i][j]=read(),sum[i][j]=a[i][j]+sum[i-1][j];
}
}
int ans1=0,ans2=0;
for(ri j=1;j<=m;++j){
if(!sum[n][j])continue;
int pre=0,pos=0;
for(ri i=n;i;--i){
if(!a[i][j])continue;
f[i][j]=sum[min(n,i+k-1)][j]-sum[i-1][j];
if(f[i][j]>=pre)pre=f[i][j],pos=i;
}
ans1+=pre,ans2+=sum[pos-1][j];
}
cout<<ans1<<' '<<ans2<<'\n';
return 0;
}
D题
传送门
题意:
现在有一个归并排序函数mergesort(l,r)mergesort(l,r)mergesort(l,r)表示将[l,r)[l,r)[l,r)位置的数给归并排序,如果已经有序会直接返回,否则会调用mergesort(l,mid)mergesort(l,mid)mergesort(l,mid)和mergesort(mid,r)mergesort(mid,r)mergesort(mid,r),现在给你nnn和kkk,要求构造出一个序列使得恰好调用kkk次这个函数能够使得排序完成,无解输出−1-1−1。
思路:
首先将这个函数递归到的区间都看成结点,这就构成了一棵线段树,然后经过对题意的理解可以发现一个显然的结论:kkk必须是一个奇数否则一定无解。
证明可以考虑数学归纳法。
然后我们一直递归左右区间,每次向下走都会产生222的贡献,走不动了就返回即可。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=2e5+5;
int n,k,siz[N<<2],ans[N];
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
inline void build(int p,int l,int r){
siz[p]=1;
if(r-l<2)return;
build(lc,l,mid),build(rc,mid,r);
siz[p]=siz[lc]+1+siz[rc];
}
inline void solve(int p,int l,int r){
if(!k||r-l<2)return;
for(ri det=0;det+l<mid&&det+mid<r;++det)swap(ans[l+det],ans[mid+det]);
k-=2;
solve(lc,l,mid);
if(!k)return;
solve(rc,mid,r);
}
#undef lc
#undef rc
#undef mid
int main(){
n=read(),k=read();
if(!(k&1))return puts("-1"),0;
build(1,0,n);
if(k>siz[1])return puts("-1"),0;
if(k==1){
for(ri i=1;i<=n;++i)cout<<i<<' ';
return 0;
}
for(ri i=0;i<n;++i)ans[i]=i+1;
--k;
solve(1,0,n);
for(ri i=0;i<n;++i)cout<<ans[i]<<' ';
return 0;
}
E题
传送门
题意:有n(n≤3000)n(n\le3000)n(n≤3000)个人参与比赛,每个人都有一个解题数,现在要决定拿金牌的人数cnt1cnt1cnt1,拿银牌的人数cnt2cnt_2cnt2,拿铜牌的人数cnt3cnt_3cnt3,各自对应一个解题数区间[d1,c1],[d2,c2],[d3,c3][d1,c1],[d2,c2],[d3,c3][d1,c1],[d2,c2],[d3,c3]
现在要求:
- d1−c2d1-c2d1−c2最大化
- 满足第一点之后d2−c3d2-c3d2−c3最大化
- 满足前两点之后d3−胸牌第一名解题数d3-胸牌第一名解题数d3−胸牌第一名解题数最大化
- 对于任意的x,y(1<=x,y<=3),cntx<=2*cnty
现在需要构造出一种合法的方案1,2,3,−11,2,3,-11,2,3,−1表示金牌,银牌,铜牌和胸牌。
思路:
考虑枚举金牌线和银牌线。这样铜牌线的可行范围是一段连续区间,我们在差分数组上建立一个ststst表取个极值即可。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=3005;
int diff[N],n,st[N][15],Log[N],p1,p2,p3,ans[N];
struct Node{
int a,id;
friend inline bool operator<(const Node&a,const Node&b){return a.a<b.a;}
}a[N];
int main(){
n=read();
for(ri i=1;i<=n;++i)a[i]=(Node){read(),i};
sort(a+1,a+n+1);
for(ri i=0;i<n;++i)diff[i]=a[i+1].a-a[i].a,st[i][0]=i;
p1=-1;
for(ri i=2;i<=n;++i)Log[i]=Log[i>>1]+1;
for(ri j=1;j<=12;++j)for(ri i=0;i<=n-(1<<j);++i)st[i][j]=diff[st[i][j-1]]>=diff[st[i+(1<<(j-1))][j-1]]?st[i][j-1]:st[i+(1<<(j-1))][j-1];
for(ri t1,t2,t3,l1,l2,i=(n+1)>>1;i<n;++i){
if(~p1&&diff[i]<diff[p1])continue;
t1=i,l1=n-i;
for(ri t,L,R,j=1;j<n;++j){
l2=i-j,t2=j;
if(2*l2<l1||2*l1<l2||j*2<l2||j*2<l1)continue;
L=(max(l1,l2)+1)/2,R=min(l1,l2)*2;
if(L>R)continue;
R=max(0,j-R),L=max(0,j-L),swap(L,R);
t=Log[R-L+1];
t3=(diff[st[L][t]]>=diff[st[R-(1<<t)+1][t]]?st[L][t]:st[R-(1<<t)+1][t]);
if(~p1){
if(diff[p1]>diff[t1])continue;
if(diff[p1]==diff[t1]&&diff[p2]>diff[t2])continue;
if(diff[p1]==diff[t1]&&diff[p2]==diff[t2]&&diff[p3]>diff[t3])continue;
}
p1=t1,p2=t2,p3=t3;
}
}
for(ri i=1;i<=p3;++i)ans[a[i].id]=-1;
for(ri i=p3+1;i<=p2;++i)ans[a[i].id]=3;
for(ri i=p2+1;i<=p1;++i)ans[a[i].id]=2;
for(ri i=p1+1;i<=n;++i)ans[a[i].id]=1;
for(ri i=1;i<=n;++i)cout<<ans[i]<<' ';
return 0;
}
F题
传送门
题意:给一个字符ttt,上面有一些禁止位置,对于每一个子串sss,f(s)f(s)f(s)表示sss在ttt中出现且结尾位置未被禁止的合法位置数,现在求∣s∣∗f(s)|s|*f(s)∣s∣∗f(s)最大值。
思路:samsamsam模板题,直接套板子即可。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
return getchar();
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=2e5+5;
typedef long long ll;
char s[N],t[N];
int n;
namespace sam{
int len[N<<1],link[N<<1],son[N<<1][26],siz[N<<1],last=1,tot=1;
inline void expand(int x,int val){
int p=last,np=++tot;
siz[last=np]=val,len[np]=len[p]+1;
while(p&&!son[p][x])son[p][x]=np,p=link[p];
if(!p){link[np]=1;return;}
int q=son[p][x],nq;
if(len[q]==len[p]+1){link[np]=q;return;}
len[nq=++tot]=len[p]+1,memcpy(son[nq],son[q],sizeof(son[q])),link[nq]=link[q];
link[q]=link[np]=nq;
while(p&&son[p][x]==q)son[p][x]=nq,p=link[p];
}
inline void solve(){
static int cnt[N<<1],rk[N<<1];
ll ans=0;
for(ri i=1;i<=tot;++i)++cnt[len[i]];
for(ri i=1;i<=tot;++i)cnt[i]+=cnt[i-1];
for(ri i=1;i<=tot;++i)rk[cnt[len[i]]--]=i;
for(ri i=tot;i^1;--i)siz[link[rk[i]]]+=siz[rk[i]];
for(ri i=1;i<=tot;++i)ans=max(ans,(ll)len[i]*siz[i]);
cout<<ans;
}
}
int main(){
n=read();
scanf("%s%s",s+1,t+1);
for(ri i=1;i<=n;++i)sam::expand(s[i]-'a',t[i]=='1'?0:1);
sam::solve();
return 0;
}
Codeforces 873 简要题解的更多相关文章
- Codeforces 863 简要题解
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 简要题解?因为最后一题太毒不想写了所以其实是部分题解... A题 传送门 题意简述:给你一个数,问你能不能通过加前导000使其成为一个回文数 ...
- Codeforces 381 简要题解
做的太糟糕了...第一题看成两人都取最优策略,写了个n^2的dp,还好pre-test良心(感觉TC和CF的pretest还是很靠谱的),让我反复过不去,仔细看题原来是取两边最大的啊!!!前30分钟就 ...
- Codeforces 1120 简要题解
文章目录 A题 B题 C题 D题 E题 F题 传送门 A题 传送门 题意简述:给你一个mmm个数的数列,现在规定把一个数列的1,2,...,k1,2,...,k1,2,...,k分成第一组,把k+1, ...
- Codeforces 1098 简要题解
文章目录 前言 A题 B题 C题 D题 E题 传送门 前言 没错因为蒟蒻太菜了这场的最后一道题也咕掉了,只有AAA至EEE的题解233 A题 传送门 题意简述:给出一棵带点权的树,根节点深度为111, ...
- Codeforces 1110 简要题解
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 众所周知ldxoildxoildxoi这种菜鸡选手是不会写HHH题的,因此该篇博客只有AAA题至GGG题的题解,实在抱歉. A题 传送门 题 ...
- Codeforces 380 简要题解
ABC见上一篇. 感觉这场比赛很有数学气息. D: 显然必须要贴着之前的人坐下. 首先考虑没有限制的方案数.就是2n - 1(我们把1固定,其他的都只有两种方案,放完后长度为n) 我们发现对于一个限制 ...
- Codeforces 845 简要题解
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 A题 传送门 题意:2n2n2n个人下棋,分为两个阵营,每个阵营nnn个人,每个人有一个积分,积分高的能赢积分低的,问如果你可以随意选人,然 ...
- Codeforces 1065 简要题解
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 GGG题略难,膜了一波zhouyuyang{\color{red} zhouyuyang}zhouyuyang巨佬的代码. 其余都挺清真的. ...
- Codeforces 888 简要题解
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 A题 传送门 题意简述:给一个数列,问有多少个峰值点(同时比两边都大/小的点) 思路:按照题意模拟. 代码: #include<bit ...
随机推荐
- rm命令详解
1.简介: rm是常用的命令,该命令的功能为删除一个目录中的一个或多个文件或目录,它也可以将某个目录及其下的所有文件及子目录均删除.对于链接文件,只是删除了链接,原有文件均保持不变. 注意:rm是一个 ...
- True和数字相加的结果
num = 5 print(num + True) # 其结果为6
- spreed&rest
ES6变化-spreed&rest … 展开&收集运算符: 此运算符在不同地方使用有不同的功效,可以从写和读两个角度考虑. 写:function test (…arg){}; test ...
- NET(C#):关于正确读取中文编码文件
https://blog.csdn.net/ma_jiang/article/details/53213442 首先如果读者对编码或者BOM还不熟悉的话,推荐先读这篇文章:.NET(C#):字符编码( ...
- Vue如何更新子组件
黑科技: 给子组件绑定一个key值,当key值改变时,子组件就会更新 ~
- gym 101982 B题 Coprime Integers
题目链接:https://codeforces.com/gym/101982/attachments 贴一张图吧: 题目意思就是给出四个数字,a,b,c,d,分别代表两个区间[a,b],[c,d],从 ...
- logistics回归理解
多元回归方程:假设有一个因变量y和一组自变量x1, x2, x3, ... , xn,其中y为连续变量,我们可以拟合一个线性方程: y =β0 +β1*x1 +β2*x2 +β3*x3 +...+βn ...
- MAC配置VIM环境
Ruby开发环境配置 ~/.vimrc set nocompatible " be iMproved, required filetype off " required set r ...
- Tomcat开启本地库(Apache Tomcat Native Library)支持
操作系统环境:Ubuntu 17 amd64位 软件环境:Tomcat 9 tomcat安装位置:/opt/tomcat JDK:1.8.144 64位 安装步骤: 1:编译安装 cd /opt/t ...
- Python中安装bs4后,pycharm依然报错ModuleNotFoundError: No module named 'bs4'
学习网络抓取时,第一步出现问题. 执行示例代码 from urllib.request import urlopen from bs4 import BeautifulSoup html = urlo ...