您的位置:首页 > 其它

Educational Codeforces Round 38 题解

2018-02-18 12:51 375 查看

总结

A由于阅读水平不够看了好久才看懂。这次的edu比之前我做的一场难了,D其实很简单但我往另一个方向想了,所以没有做出来,倒是E很快就切了。

这是最终成绩:



题解

A. Word Correction

无聊题,怎么做都行。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

int n;
char s[105];

bool check(char c)
{
return c=='a'||c=='e'||c=='i'||c=='o'||c=='u'||c=='y';
}

int main()
{
scanf("%d",&n);
scanf("%s",s+1);
int flag=0;
for (int i=1;i<=n;i++)
{
if (check(s[i])&&check(s[i-1])) continue;
putchar(s[i]);
}
return 0;
}


B. Run For Your Prize

直接双指针搞搞就好。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=100005;
const int inf=1000000;

int n,a
;

int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

int main()
{
n=read();
for (int i=1;i<=n;i++) a[i]=read();
int l=0,r=n+1,ans=0;
while (l+1<r)
{
if (a[l+1]-1<=inf-a[r-1]) l++,ans=max(ans,a[l]-1);
else r--,ans=max(ans,inf-a[r]);
}
printf("%d",ans);
return 0;
}


C. Constructing Tests

列出式子后拆成完全平方式,然后通过枚举因数来暴力查找合法解即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

int n;

int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

int main()
{
int T=read();
while (T--)
{
n=read();
if (!n) {printf("%d %d\n",1,1);continue;}
int flag=0;
for (int i=1;i*i<=n;i++)
if (n%i==0)
{
if ((i&1)!=((n/i)&1)||i*i==n) continue;
int x=(i+n/i)/2,y=(n/i-i)/2;
if (x/(x/y)!=y) continue;
printf("%d %d\n",x,x/y);
flag=1;break;
}
if (!flag) puts("-1");
}
return 0;
}


D. Buy a Ticket

一开始想的是各种贪心,发现都不行。实际上只要新建一个超级点s,然后s往每个点连权值为点权的边。那么每个点到s的最短路就是该点的答案了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define mp(x,y) make_pair(x,y)
using namespace std;

typedef long long LL;
typedef pair<LL,int> pi;

const int N=200005;
const LL inf=(LL)1e18;

int n,m,cnt,last
;
LL dis
;
bool vis
;
struct edge{int to,next;LL w;}e[N*4];
priority_queue<pi> que;

void addedge(int u,int v,LL w)
{
e[++cnt].to=v;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].w=w;e[cnt].next=last[v];last[v]=cnt;
}

void dij()
{
for (int i=1;i<=n;i++) dis[i]=inf;
que.push(mp(0,0));
while (!que.empty())
{
int x=que.top().second;que.pop();
while (!que.empty()&&vis[x]) x=que.top().second,que.pop();
if (vis[x]) break;
vis[x]=1;
for (int i=last[x];i;i=e[i].next)
if (dis[x]+e[i].w<dis[e[i].to])
{
dis[e[i].to]=dis[x]+e[i].w;
que.push(mp(-dis[e[i].to],e[i].to));
}
}
}

int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y;LL z;scanf("%d%d%I64d",&x,&y,&z);
addedge(x,y,z*2);
}
for (int i=1;i<=n;i++)
{
LL w;scanf("%I64d",&w);
addedge(0,i,w);
}
dij();
for (int i=1;i<=n;i++) printf("%I64d ",dis[i]);
return 0;
}


E. Max History

构造f的过程可以看成是在倒着维护一个单调递减的单调栈。我们可以单独考虑每一个数的贡献。一个数出现在单调栈里面当且仅当其前面没有不小于他的数。那么就可以把比他大的数全放在他后面,比他小的数就用隔板法算一算方案即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long LL;

const int N=1000005;
const int MOD=1000000007;

int n,a
,jc
,ny
;

int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

int C(int n,int m)
{
return (LL)jc
*ny[m]%MOD*ny[n-m]%MOD;
}

int main()
{
n=read();
for (int i=1;i<=n;i++) a[i]=read();
sort(a+1,a+n+1);
jc[0]=jc[1]=ny[0]=ny[1]=1;
for (int i=2;i<=n;i++) jc[i]=(LL)jc[i-1]*i%MOD,ny[i]=(LL)(MOD-MOD/i)*ny[MOD%i]%MOD;
for (int i=2;i<=n;i++) ny[i]=(LL)ny[i]*ny[i-1]%MOD;
int ans=0;
for (int i=1;i<=n;i++)
{
int j=i,s=i-1;
while (j<n&&a[j+1]==a[j]) j++;
(ans+=(LL)jc[s]*jc[n-s-1]%MOD*C(n,s)%MOD*a[i]%MOD*(j-i+1)%MOD)%=MOD;
i=j;
}
(ans+=MOD-(LL)a
*jc
%MOD)%=MOD;
printf("%d",ans);
return 0;
}


F. Erasing Substrings

这题比较厉害。最暴力的想法就是设dp[m][mask]表示在对一个前缀进行了mask里面的操作后,得到了最终串长度为m的最小前缀。这样的话我们还要储存一个字符串,时空复杂度显然不能接受。

但不难发现对于两个状态dp[m][mask1]和dp[m][mask2],字典序较大的那个肯定不可能成为最终答案。那么我们就可以对每个状态只存一个布尔值,表示该状态能否成为最终串的前缀。

怎么计算这个呢?假设现在由长度m转移到长度m+1,那么我们就在所有状态的后一个字符里面找一个最小的,来作为第m+1个字符,然后更新dp[m+1][mask]的状态即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=5005;

int n,m,r;
char s
,ans
;
bool f
,g
;

int main()
{
scanf("%s",s+1);n=strlen(s+1);
for (r=1;r*2<=n;r*=2);
m=n-r+1;
for (int i=0;i<r;i++) f[i]=1;
for (int i=1;i<=m;i++)
{
ans[i]='z';
for (int j=0;j<r;j++) if (f[j]&&s[i+j]<ans[i]) ans[i]=s[i+j];
memset(g,0,sizeof(g));
for (int j=0;j<r;j++)
if (f[j]&&s[i+j]==ans[i]&&!g[j])
{
int w=r-1-j;
for (int s=w;s;s=(s-1)&w) g[r-1-s]=1;
g[r-1]=1;
}
for (int j=0;j<r;j++) f[j]=g[j];
}
for (int i=1;i<=m;i++) putchar(ans[i]);
return 0;
}


G. Shortest Path Queries

题解
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: