Codeforces Round #543 Div1题解(并不全)
Codeforces Round #543 Div1题解
A. Diana and Liana
给定一个长度为\(m\)的序列,你可以从中删去不超过\(m-n*k\)个元素,剩下的元素从左往右每\(k\)个一组,最后一组可以不满。给定你一个大小为\(|S|\)的可重集,要求你分出的组中至少有一组构成的可重集包含了给定的可重集。
构造一种符合条件的删数方案。
\(n,m,k,|S|\le 5*10^5\)
写了\(1h\)才过,感觉身败名裂。
考虑枚举一个右端点\(r\),显然可以确定一个最大的\(l\)恰好包含了这个可重集,那么\(check\)一下这段\([l,r]\)是否满足条件就好了。显然这个\(l\)随着\(r\)向右移动也是单调的。
然后\(WA\)了半天,最后为了方便,强制\(r-l+1\ge k\),这样子只需要在\(l\)之前删掉\((l-1)\%k\)个,在\([l,r]\)之间删去\(r-l+1-k\)个,就很好写了。。。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 500500
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int m,K,n,S,tot,Del,a[MAX],b[MAX],c[MAX],d[MAX];
int main()
{
m=read();K=read();n=read();S=read();Del=m-K*n;
for(int i=1;i<=m;++i)a[i]=read();
for(int i=1;i<=S;++i)if(!b[read()]++)++tot;
for(int l=1,r=1;r<=m;++r)
{
++c[a[r]];tot-=c[a[r]]==b[a[r]];
while(!tot&&r-l+1>K&&l<=m&&c[a[l]]>b[a[l]])--c[a[l]],++l;
if(!tot&&r-l+1>=K)
{
int v=(l-1)%K+r-l+1-K;
if(v>Del)continue;
printf("%d\n",v);if(!v)return 0;
for(int i=1;i<=(l-1)%K&&v;++i)printf("%d ",i),--v;
for(int i=l;i<=r&&v;++i)
if(d[a[i]]+1>b[a[i]])
printf("%d ",i),--v;
else d[a[i]]+=1;
return 0;
}
}
puts("-1");
return 0;
}
B. Once in a casino
你有一个长度为\(n\)的,值域为\(0-9\)的元素序列,每次可以给相邻两个元素同时加一或者减一,但是仍然要在\(0-9\)的范围之内。回答能否把当前这些元素变成给定的某个元素序列,如果可以输出方案的前\(10^5\)步,否则输出\(-1\)。
\(n\le 10^5\)。
首先不需要考虑在值域范围内的问题,从头到尾依次算一下,看看能否变过去就行了。
现在构造方案,比如说你现在要给\(x,x+1\)位置加一,但是\(x+1\)位置是\(9\),那么你就递归处理,先让\(x+1\)位置减去一个\(1\),递归回来之后再给\(x,x+1\)位置\(+1\)。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 100100
int n,a[MAX],b[MAX],c[MAX];long long ans;char ch[MAX];
void init(int *a){scanf("%s",ch+1);for(int i=1;i<=n;++i)a[i]=ch[i]-48;}
void dfs(int x,int w)
{
if(!ans)return;
if(0<=a[x+1]+w&&a[x+1]+w<=9){printf("%d %d\n",x,w);a[x]+=w,a[x+1]+=w;--ans;return;}
dfs(x+1,-w);if(!ans)return;printf("%d %d\n",x,w);a[x]+=w;a[x+1]+=w;--ans;
}
int main()
{
scanf("%d",&n);init(a);init(b);
for(int i=1;i<=n;++i)c[i]=a[i];
for(int i=1;i<n;++i){int d=b[i]-c[i];c[i]+=d;c[i+1]+=d;ans+=abs(d);}
if(c[n]!=b[n]){puts("-1");return 0;}
cout<<ans<<endl;ans=min(ans,100000ll);
for(int i=1;i<n&&ans>0;++i)
while(a[i]!=b[i]&&ans>0)dfs(i,(b[i]-a[i])/abs(b[i]-a[i]));
return 0;
}
C. Compress String
给定一个串,你可以把它进行划分,有两种划分方式:要么是一个字符成一组,代价是\(a\);要么是\([l,r]\)划分一组,要求\([l,r]\)是\([1,l-1]\)的一个子串,代价是\(b\)。求最小代价。
\(|S|\le 5000\)。
一边构建\(SAM\)一边\(dp\),就很简单。。。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 5050
int n,a,b,f[MAX];char s[MAX];
struct Node{int son[26],ff,len;}t[MAX<<1];
int tot=1,last=1;
void extend(int c)
{
int p=last,np=++tot;last=np;t[np].len=t[p].len+1;
while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff;
if(!p)t[np].ff=1;
else
{
int q=t[p].son[c];
if(t[q].len==t[p].len+1)t[np].ff=q;
else
{
int nq=++tot;
t[nq]=t[q];t[nq].len=t[p].len+1;
t[np].ff=t[q].ff=nq;
while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff;
}
}
}
int main()
{
scanf("%d%d%d%s",&n,&a,&b,s+1);
for(int i=1;i<=n;++i)f[i]=1e9;
for(int i=1;i<=n;++i)
{
extend(s[i]-97);f[i]=min(f[i],f[i-1]+a);
for(int j=i+1,u=1;j<=n;++j)
{
int c=s[j]-97;
if(!t[u].son[c])break;
f[j]=min(f[j],f[i]+b);
u=t[u].son[c];
}
}
printf("%d\n",f[n]);
return 0;
}
D. Power Tree
给定一棵树,每个点你可以选或者不选,如果选就有一个代价,现在对于每个叶子节点,要求其到根节点的路径上选择的点的集合必须非空且两两不同,求最小代价。
\(n\le 200000\)。
如果有\(k\)个叶子节点,那么一定会被选择\(k\)个点。
如果一个节点的儿子有多个叶子节点,那么至多只会有一个叶子节点不被选择。因此每个点的子树内要么选择了叶子节点个数个节点,要么是叶子个数减一。那么设\(f[u][j=0/1]\)表示这个子树内选择了叶子节点个数\(-j\)个节点的最小代价。
考虑如何转移:
\(f[u][1]=\min_v\{f[v][1]+\sum_{w\neq v}f[w][0]\}\)
\(f[u][0]=\min\{\sum f[v][1],f[u][0]+c[u]\}\)
对于求解每个点是否可能在最优方案中,则倒着\(dp\)再处理一遍就行了。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define MAX 200200
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int n,c[MAX],S[MAX],top;ll f[MAX][2];
bool leaf(int u){return !e[h[u]].next;}
void dfs(int u,int ff)
{
ll s=0;if(ff&&leaf(u)){f[u][1]=c[u];f[u][0]=0;return;}
f[u][0]=f[u][1]=1e18;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)dfs(e[i].v,u),s+=f[e[i].v][1];
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)f[u][0]=min(f[u][0],s-f[e[i].v][1]+f[e[i].v][0]);
f[u][1]=min(s,f[u][0]+c[u]);
}
bool visf[MAX][2];
void find(int u,int ff)
{
if(visf[u][1])
{
if(f[u][1]==f[u][0]+c[u])S[++top]=u,visf[u][0]=true;
ll s=0;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)s+=f[e[i].v][1];
if(f[u][1]==s)
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)visf[e[i].v][1]=true;
}
if(visf[u][0])
{
ll tmp=1e18;int tot=0;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)tmp=min(tmp,f[e[i].v][0]-f[e[i].v][1]);
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)tot+=(tmp==f[e[i].v][0]-f[e[i].v][1]);
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)
{
if(tot>1||tmp<f[e[i].v][0]-f[e[i].v][1])visf[e[i].v][1]=true;
if(tmp==f[e[i].v][0]-f[e[i].v][1])visf[e[i].v][0]=true;
}
}
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)find(e[i].v,u);
}
int main()
{
n=read();
for(int i=1;i<=n;++i)c[i]=read();
for(int i=1,u,v;i<n;++i)u=read(),v=read(),Add(u,v),Add(v,u);
dfs(1,0);
printf("%I64d ",f[1][1]);visf[1][1]=true;
find(1,0);sort(&S[1],&S[top+1]);
printf("%d\n",top);for(int i=1;i<=top;++i)printf("%d ",S[i]);puts("");
return 0;
}
QwQ
剩下的题它们都鸽了。
主要是前面把我写自闭了
Codeforces Round #543 Div1题解(并不全)的更多相关文章
- Codeforces Round #545 Div1 题解
Codeforces Round #545 Div1 题解 来写题解啦QwQ 本来想上红的,结果没做出D.... A. Skyscrapers CF1137A 题意 给定一个\(n*m\)的网格,每个 ...
- Codeforces Round #539 Div1 题解
Codeforces Round #539 Div1 题解 听说这场很适合上分QwQ 然而太晚了QaQ A. Sasha and a Bit of Relax 翻译 有一个长度为\(n\)的数组,问有 ...
- Educational Codeforces Round 64 部分题解
Educational Codeforces Round 64 部分题解 不更了不更了 CF1156D 0-1-Tree 有一棵树,边权都是0或1.定义点对\(x,y(x\neq y)\)合法当且仅当 ...
- Educational Codeforces Round 64部分题解
Educational Codeforces Round 64部分题解 A 题目大意:给定三角形(高等于低的等腰),正方形,圆,在满足其高,边长,半径最大(保证在上一个图形的内部)的前提下. 判断交点 ...
- Codeforces Round div2 #541 题解
codeforces Round #541 abstract: I构造题可能代码简单证明很难 II拓扑排序 III并查集 启发式排序,带链表 IV dp 处理字符串递推问题 V 数据结构巧用:于二叉树 ...
- [Codeforces Round #254 div1] C.DZY Loves Colors 【线段树】
题目链接:CF Round #254 div1 C 题目分析 这道题目是要实现区间赋值的操作,同时还要根据区间中原先的值修改区间上的属性权值. 如果直接使用普通的线段树区间赋值的方法,当一个节点表示的 ...
- [Codeforces Round #461 (Div2)] 题解
[比赛链接] http://codeforces.com/contest/922 [题解] Problem A. Cloning Toys [算法] 当y = 0 , 不可以 当 ...
- Educational Codeforces Round 63部分题解
Educational Codeforces Round 63 A 题目大意就不写了. 挺简单的,若果字符本来就单调不降,那么就不需要修改 否则找到第一次下降的位置和前面的换就好了. #include ...
- Codeforces Round #596 Div1 A~E题解
我好菜啊 A 题意: 定义p-二进制数为2^k-p,给出n和p,求用最小个数的p-二进制数来表示n 1<=n<=10^9,-1000<=p<=1000 题解: 猜结论,答案不会 ...
随机推荐
- 使用git将本地项目推送到码云私有仓库
https://blog.csdn.net/qq_33876553/article/details/80111946 2018年04月27日 19:53:33 桥路丶 阅读数:2958 前言 之前博主 ...
- Python_生成随机百分比的方法
可以使用random模块去实现,给定1到100的空间,使用random的choice的方法随机选取一个数字,当这个数字在某个区间时就可以认定为出发了指定的百分比的概率. 这个简单的逻辑也可以在需要时扩 ...
- js总结:对于字符串的切割截取和合并
1.函数:split() 功能:使用一个指定的分隔符把一个字符串分割存储到数组 例子: str=”jpg|bmp|gif|ico|png”; arr=str.split(”|”); //arr是一个包 ...
- js判断一个对象{}是否为空对象,没有任何属性
// js如何判断一个对象{}是否为空对象,没有任何属性 if (typeof model.rows === "object" && !(model.rows in ...
- Linux用户权限指令, 定时任务等指令
一. 网卡配置详解 网络配置文件: /etc/sysconfig/network 网络接口配置文件: /etc/sysconfig/network-scripts/ifcfg-INTERFACE_NA ...
- Object...与Object[]使用的一点区别和记录
Object是所有类的基类 简述: Object ...objects(称为可变个数的形参)这种参数定义是在不确定方法参数的情况下的一种多态表现形式.Java可变参数,即这个方法可以传递多个参数,这个 ...
- QTP 自动化测试--点滴 等待
1 使用wait()语句:wait(10) 等待10秒后继续执行 Window("驷惠WIN系列[汽车4S连锁管理软件] 6.").Window("应付帐款明细查询&qu ...
- Lodop控件NewPage();测试输出空白页
LODOP.NewPage();和LODOP.NewPageA();是强制分页语句,两者的区别可查看本博客的相关博文:Lodop强制分页LODOP.NewPage()和LODOP.NewPageA() ...
- NaN与Null与undefiined的关系
在js中,定义一个变量需要通过关键字var来定义,定义的变量可以是字符串.数字等等都行.但是如果你只是定义了一个变量,没有给他赋值,那么它就默认为'undefined'.例如 var name; co ...
- Vivado安装、生成bit文件及烧录FPGA的简要流程
https://wenku.baidu.com/view/0294cbb3bb4cf7ec4bfed01a.html