蒟蒻就切了四道水题,然后EF看着可写然而并不会,中间还WA了一次,我太菜了.jpg =。=

A.Vasya And Password

一开始看着有点虚没敢立刻写,后来写完第二题发现可以暴力讨论,因为保证有解,没了

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
char rd[N];
int main ()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",rd);
int c1=,c2=,c3=,len=strlen(rd);
for(int i=;i<len;i++)
{
if(rd[i]>=''&&rd[i]<='') c1++;
if(rd[i]>='A'&&rd[i]<='Z') c2++;
if(rd[i]>='a'&&rd[i]<='z') c3++;
}
if(!c1&&!c2&&c3)
rd[]='',rd[]='A';
else if(!c1&&c2&&!c3)
rd[]='',rd[]='a';
else if(c1&&!c2&&!c3)
rd[]='a',rd[]='A';
else if(c1&&c2&&!c3)
{
if(c1>)
{
for(int i=;i<len;i++)
if(rd[i]>=''&&rd[i]<='') {rd[i]='a';break;}
}
else if(c2>)
{
for(int i=;i<len;i++)
if(rd[i]>='A'&&rd[i]<='Z') {rd[i]='a';break;}
}
}
else if(c1&&!c2&&c3)
{
if(c1>)
{
for(int i=;i<len;i++)
if(rd[i]>=''&&rd[i]<='') {rd[i]='A';break;}
}
else if(c3>)
{
for(int i=;i<len;i++)
if(rd[i]>='a'&&rd[i]<='z') {rd[i]='A';break;}
}
}
else if(!c1&&c2&&c3)
{
if(c3>)
{
for(int i=;i<len;i++)
if(rd[i]>='a'&&rd[i]<='z') {rd[i]='';break;}
}
else if(c2>)
{
for(int i=;i<len;i++)
if(rd[i]>='A'&&rd[i]<='Z') {rd[i]='';break;}
}
}
for(int i=;i<len;i++) printf("%c",rd[i]); printf("\n");
}
return ;
}

B.Relatively Prime Pairs

想了一会一拍脑袋,这题\*\*这么水还想啥,输出相邻数字,没了

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long l,r;
int main ()
{
scanf("%lld%lld",&l,&r);
printf("YES\n");
for(long long i=l;i<=r;i+=)
printf("%lld %lld\n",i,i+);
return ;
}

C.Vasya and Multisets

需要稍微想一想的题,然而本质上还是个分类讨论

考虑每种数字出现不同次数带来的影响,出现一次的一定对一个集合有贡献,出现两次的怎么放都没有影响,出现三次及以上的可以令它对一个集合有贡献,也可以令它没有影响

所以首先除去所有出现两次的数(都丢给一个集合即可),然后看看出现一次的有奇数个还是偶数个。如果有奇数个且没有出现三次以上的则无解;如果有奇数个且有出现三次及以上的就先两两分开出现一次的,把剩下那个放在一个集合,出现三次及以上的一个数放一个在另一个集合,然后剩下的一股脑丢在一个集合里;如果有偶数个就两两分开然后剩下的直接丢在一个集合里

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
long long num[N],cnt[N];
char outp[N];
bool used[N];
long long n,und,ans,k;
int main ()
{
scanf("%lld",&n);
for(int i=;i<=n;i++)
scanf("%lld",&num[i]),cnt[num[i]]++;
for(int i=;i<=;i++)
if(cnt[i]==)
{
for(int j=;j<=n;j++)
if(num[j]==i) used[j]=,outp[j]='A';
}
else if(cnt[i]>=)
{
und++;
for(int j=;j<=n;j++)
if(num[j]==i) used[j]=;
}
// for(int i=1;i<=n;i++) printf("%c",outp[i]);
for(int i=;i<=n;i++) if(!used[i]) ans++,outp[i]=(k^=)?'A':'B';
if((ans&)&&!und) {printf("NO");return ;}
else
{
if((ans&)==)
{for(int i=;i<=n;i++) if(used[i]) outp[i]='A';
}
else
{
bool flag=true;
for(int i=;i<=n;i++) if(used[i]&&cnt[num[i]]!=)
{
if(flag)outp[i]='B',flag=false;
else outp[i]='A';
}
}
}
printf("YES\n");
for(int i=;i<=n;i++)
printf("%c",outp[i]);
return ;
}

D.Bicolorings

递推题,画图推式子即可

设$rec[i][j][0/1][0/1]$表示到第$i$列分出了$j$块,且第$i$列上面为白/黑,下面为白/黑的方案数,这样就足够递推了,讨论新加入的两块与之前的联通情况即可

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
const long long mod=;
long long rec[N][*N][][];
long long n,m;
int main ()
{
scanf("%lld%lld",&n,&m);
rec[][][][]=rec[][][][]=;
rec[][][][]=rec[][][][]=;
for(int i=;i<=n;i++)
for(int j=;j<=*i;j++)
{
rec[i][j][][]+=rec[i-][j][][]+rec[i-][j][][]+rec[i-][j][][]+rec[i-][j-][][];
rec[i][j][][]+=rec[i-][j][][]+rec[i-][j][][]+rec[i-][j][][]+rec[i-][j-][][];
rec[i][j][][]+=rec[i-][j][][]+rec[i-][j-][][]+rec[i-][j-][][]; if(j>=) rec[i][j][][]+=rec[i-][j-][][];
rec[i][j][][]+=rec[i-][j][][]+rec[i-][j-][][]+rec[i-][j-][][]; if(j>=) rec[i][j][][]+=rec[i-][j-][][];
rec[i][j][][]%=mod;rec[i][j][][]%=mod;rec[i][j][][]%=mod;rec[i][j][][]%=mod;
}
printf("%lld",(rec[n][m][][]+rec[n][m][][]+rec[n][m][][]+rec[n][m][][])%mod);
return ;
}

E.Vasya and Big Integers

看这个范围,显然是个线性DP题然而你是个不会做DP的鶸

看了看AC代码没看懂,先咕着,等官方题解=。=

哦官方题解我也没看懂,弃疗了

F.The Shortest Statement

题目并不难......

看出题人都特意提示了$m-n<=20$我居然还没做出来,我太菜了=。=

先随便跑一棵搜索树出来,对于指回祖先的边特殊记录下这些祖先,然后continue掉,单独把这些祖先拿出来预处理最短路,然后回答询问的时候除了在搜索树上求一个树上距离再考虑一下这些祖先到两点的最短路之和就行了

调试的时候持续石乐志,出了一堆**错误......

 #include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,K=;
struct a
{
int node;
long long dist;
};
bool operator < (a x,a y)
{
return x.dist>y.dist;
}
priority_queue<a> hp;
int p[N],noww[*N],goal[*N],mem[K];
int siz[N],dep[N],anc[N],imp[N],top[N];
long long val[*N],dis[N],diss[K][N];
int n,m,q,t1,t2,cnt,len,tot;
long long t3;
bool vis[N],bac[N];
void link(int f,int t,long long v)
{
noww[++cnt]=p[f],p[f]=cnt;
goal[cnt]=t,val[cnt]=v;
}
void DFS(int nde,int fth,int dth)
{//printf("%d->%d\n",fth,nde);
int tmp=;
siz[nde]=,anc[nde]=fth,dep[nde]=dth;
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=fth)
{
if(dep[goal[i]])
{
if(dep[goal[i]]<dep[nde])
mem[++len]=goal[i];
continue;
}
dis[goal[i]]=dis[nde]+val[i];
DFS(goal[i],nde,dth+);
siz[nde]+=siz[goal[i]];
if(siz[goal[i]]>tmp)
tmp=siz[goal[i]],imp[nde]=goal[i];
}
}
void MARK(int nde,int tpp)
{
top[nde]=tpp;
if(imp[nde])
{
MARK(imp[nde],tpp);
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=anc[nde]&&goal[i]!=imp[nde])
if(dep[goal[i]]>dep[nde]) MARK(goal[i],goal[i]);
}
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y); x=anc[top[x]];
}
return dep[x]<dep[y]?x:y;
}
void Dijkstra(int nde,int typ)
{
memset(diss[typ],0x3f,sizeof diss[typ]);
memset(vis,,sizeof vis); diss[typ][nde]=; hp.push((a){nde,});
while(!hp.empty())
{
a tt=hp.top(); hp.pop(); int tn=tt.node;
if(vis[tn]) continue; vis[tn]=true;
for(int i=p[tn];i;i=noww[i])
if(diss[typ][goal[i]]>diss[typ][tn]+val[i])
{
diss[typ][goal[i]]=diss[typ][tn]+val[i];
hp.push((a){goal[i],diss[typ][goal[i]]});
}
}
}
long long getdis(int n1,int n2)
{
int lca=LCA(n1,n2);
return dis[n1]+dis[n2]-*dis[lca];
}
int main ()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
scanf("%d%d%lld",&t1,&t2,&t3);
link(t1,t2,t3),link(t2,t1,t3);
}
DFS(,,); MARK(,);
sort(mem+,mem++len);
len=unique(mem+,mem++len)-mem-;
for(int i=;i<=len;i++) Dijkstra(mem[i],i);
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&t1,&t2);
long long ans=getdis(t1,t2);
for(int i=;i<=len;i++)
ans=min(ans,diss[i][t1]+diss[i][t2]);
printf("%lld\n",ans);
}
return ;
}

G.Distinctification

看了官方题解,大概了解是什么思路了,但是这题解真的挺抽象的=。=

我们假设这些$pair$已经按照$a$从小到大排好序,那么我们考虑分成若干段来处理这个问题,分割的标准就是这一段首尾的距离大于等于首尾之差,也就是说这一段需要通过操作$1$来变得合法,我们就将它们划成一段,来在段内处理问题。

那么段内如何处理呢?显然我们首先将它调整成合法的情况,然后应该在段内将$b$从大到小排序,这样进行操作$2$最优,那么我们就需要用一个数据结构来维护段的信息。最后当我们处理完了所有的段,我们还需要快速将它们合并。对于合并,我们检查新加进来的$pair$左右相邻的位置,看看是否有其他段的右/左端点,有就合成一段。主要思想大概就是这样,然后说一点具体实现

对于段内的统计,我们需要统计一段区间(权值)$(l,r)$的左边的总和乘上右边的数量,然后减掉一个前缀和,统计的部分可以用权值线段树来实现。然后对于段的维护可以使用并查集,最后是段的合并,因为用线段树维护,所以就用线段树合并做就(=。=?)好了

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,M=;
long long sum[M],val[M],fsum[N];
int node[N],siz[M],son[M][];
int e[N],a[N],b[N],aset[N];
long long n,c,cnt;
int finds(int x)
{
return x==aset[x]?x:aset[x]=finds(aset[x]);
}
void pushup(int nde)
{
int ls=son[nde][],rs=son[nde][];
sum[nde]=sum[ls]+sum[rs],siz[nde]=siz[ls]+siz[rs];
val[nde]=val[ls]+val[rs]+1ll*sum[ls]*siz[rs];
}
void Create(int &nde,int l,int r,int pos,int task)
{
if(!nde) nde=++cnt;
if(l==r)
siz[nde]=,sum[nde]=val[nde]=task;
else
{
int mid=(l+r)/;
if(pos<=mid) Create(son[nde][],l,mid,pos,task);
else Create(son[nde][],mid+,r,pos,task); pushup(nde);
}
}
int Merge(int x,int y)//线段树合并
{
if(!x||!y) return x|y; int tmp=x;
son[tmp][]=Merge(son[x][],son[y][]);
son[tmp][]=Merge(son[x][],son[y][]);
if(!son[tmp][]&&!son[tmp][])
{
val[tmp]=val[x]+val[y]+1ll*sum[y]*siz[x];
sum[tmp]=sum[x]+sum[y];
siz[tmp]=siz[x]+siz[y];
}
else pushup(tmp);
return tmp;
}
long long query(int nde)
{
int nd=node[nde];
return val[nd]+1ll*(nde-)*sum[nd];
}
void gather(int a,int b)
{
int f1=finds(a),f2=finds(b);//合并两段
aset[f2]=f1,c-=query(f1),c-=query(f2);
node[f1]=Merge(node[f1],node[f2]),c+=query(f1);
}
int main ()
{
scanf("%lld",&n);
for(int i=;i<=;i++) aset[i]=i;
for(int i=;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
fsum[i]=fsum[i-]+1ll*a[i]*b[i];//预处理前缀和
a[i]=finds(a[i]),aset[a[i]]=a[i]+;//并查集维护段的情况
Create(node[a[i]],,,b[i],b[i]);
}
for(int i=;i<=;i++) aset[i]=i;
for(int i=;i<=n;i++)
{
c+=query(a[i]);
if(e[a[i]+]) gather(a[i],a[i]+);//检查左右是否有段
if(e[a[i]-]) gather(a[i]-,a[i]);
e[a[i]]=true,printf("%lld\n",c-fsum[i]);
}
return ;
}

2018.9.20 Educational Codeforces Round 51的更多相关文章

  1. Educational Codeforces Round 51 F. The Shortest Statement(lca+最短路)

    https://codeforces.com/contest/1051/problem/F 题意 给一个带权联通无向图,n个点,m条边,q个询问,询问两点之间的最短路 其中 m-n<=20,1& ...

  2. Educational Codeforces Round 51 (Rated for Div. 2) G. Distinctification(线段树合并 + 并查集)

    题意 给出一个长度为 \(n\) 序列 , 每个位置有 \(a_i , b_i\) 两个参数 , \(b_i\) 互不相同 ,你可以进行任意次如下的两种操作 : 若存在 \(j \not = i\) ...

  3. Educational Codeforces Round 51 D. Bicolorings(dp)

    https://codeforces.com/contest/1051/problem/D 题意 一个2*n的矩阵,你可以用黑白格子去填充他,求联通块数目等于k的方案数,答案%998244353. 思 ...

  4. CodeForces Educational Codeforces Round 51 (Rated for Div. 2)

    A:Vasya And Password 代码: #include<bits/stdc++.h> using namespace std; #define Fopen freopen(&q ...

  5. The Shortest Statement(Educational Codeforces Round 51 (Rated for Div.2)+最短路+LCA+最小生成树)

    题目链接 传送门 题面 题意 给你一张有\(n\)个点\(m\)条边的联通图(其中\(m\leq n+20)\),\(q\)次查询,每次询问\(u\)与\(v\)之间的最短路. 思路 由于边数最多只比 ...

  6. Educational Codeforces Round 51 (Rated for Div. 2) F - The Shortest Statement 倍增LCA + 最短路

    F - The Shortest Statement emmm, 比赛的时候没有想到如何利用非树边. 其实感觉很简单.. 对于一个询问答案分为两部分求: 第一部分:只经过树边,用倍增就能求出来啦. 第 ...

  7. Educational Codeforces Round 51 (Rated for Div. 2)

    做了四个题.. A. Vasya And Password 直接特判即可,,为啥泥萌都说难写,,,, 这个子串实际上是忽悠人的,因为每次改一个字符就可以 我靠我居然被hack了???? %……& ...

  8. Educational Codeforces Round 51 (Rated for Div. 2) The Shortest Statement

    题目链接:The Shortest Statement 今天又在群里看到一个同学问$n$个$n$条边,怎么查询两点直接最短路.看来这种题还挺常见的. 为什么最终答案要从42个点的最短路(到$x,y$) ...

  9. 【 Educational Codeforces Round 51 (Rated for Div. 2) F】The Shortest Statement

    [链接] 我是链接,点我呀:) [题意] [题解] 先处理出来任意一棵树. 然后把不是树上的边处理出来 对于每一条非树边的点(最多21*2个点) 在原图上,做dijkstra 这样就能处理出来这些非树 ...

随机推荐

  1. Flink HA

    standalone 模式的高可用 部署 flink 使用zookeeper协调多个运行的jobmanager,所以要启用flink HA 你需要把高可用模式设置成zookeeper,配置zookee ...

  2. ats 分层缓存

    了解缓存层次结构 缓存层次结构由彼此通信的缓存级别组成.ats支持多种类型的缓存层次结构. 所有缓存层次结构都识别父和子的概念. 父缓存是层次结构中较高的缓存, ats可以 将请求转发到该缓存.子缓存 ...

  3. Hyperledger Fabric Capabilities——超级账本功能汇总

    Hyperledger Fabric是一种模块化的区块链架构,是分布式记账技术(DLT)的一种独特的实现,它提供了可供企业运用的网络,具备安全.可伸缩.加密和可执行等特性.Hyperledger Fa ...

  4. hadoop之定制自己的sort过程

    Key排序 1. 继承WritableComparator 在hadoop之Shuffle和Sort中,可以看到mapper的输出文件spill文件需要在内存中排序,并且在输入reducer之前,不同 ...

  5. Metasploit拿Shell

    进入metasploit系统 msfconsole Nmap端口扫描 nmap –sV IP(或者域名),如果机器设置有防火墙禁ping,可以使用nmap -P0(或者-Pn) –sV IP(或者域名 ...

  6. 遇到执行SQL 的参数最大个数

    报错: 传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确.此 RPC 请求中提供了过多的参数.最多应为 2100. 现象是: SQL 执行的参数过多,超过了 最大值 :2100 个. ...

  7. fullPage全屏高度自适应

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  8. SGU 223 little kings BSOJ2772 状压DP

    1896 [SCOI2005]互不侵犯King [问题描述]在n*n(1<=n<=10)的棋盘上放k(0<=k<=n*n)个国王(可攻击相邻的8 个格子),求使它们无法互相攻击 ...

  9. Hibernate 延迟加载 分析

    出处:http://www.ibm.com/developerworks/cn/java/j-lo-hibernatelazy/#icomments Hibernate 的延迟加载(lazy load ...

  10. Python入门:类与类的继承

    类,是一些有共同特征和行为事物的抽象概念的总和. 1. 定义一个类: 我们使用class来定义一个类,和之前说过的定义函数用def类似.在类里面给变量赋值时,专业术语称之为类的属性. 比如拿可口可乐来 ...