Educational Codeforces Round 47 (Div 2) (A~G)


Codeforces 1009

比赛链接

hack好给力啊233
1143196-20180715161410981-1452160143.png
1143196-20180715161332300-47895845.png

A.Game Shopping

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const int N=1e3+5;

int n,m,cost[N],A[N];

inline int read()
{
    register int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}

int main()
{
    n=read(), m=read();
    for(int i=1; i<=n; ++i) cost[i]=read();
    for(int i=1; i<=m; ++i) A[i]=read();
    int now=1,ans=0;
    for(int i=1; i<=n && now<=m; ++i)
        if(cost[i]<=A[now]) ++ans, ++now;
    printf("%d\n",ans);

    return 0;
}

B.Minimum Ternary String

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
const int N=1e5+7;

int n;
char s[N],ans[N];

int main()
{
    scanf("%s",s+1), n=strlen(s+1);
    int cnt[5],now;
    cnt[0]=cnt[1]=cnt[2]=0;
    for(now=1; now<=n; ++now)
        if(s[now]!='2') ++cnt[s[now]-'0'];
        else break;
    for(int i=1; i<=cnt[0]; ++i) ans[i]='0';
    for(int i=cnt[0]+1; i<=cnt[0]+cnt[1]; ++i) ans[i]='1';
    cnt[0]=cnt[1]=cnt[2]=0;
    for(int i=now; i<=n; ++i) ++cnt[s[i]-'0'];
    for(int i=now; i<now+cnt[1]; ++i) ans[i]='1';
    s[n+1]='3';
    for(int i=now+cnt[1]; i<=n; ++i)
    {
        while(s[now]=='1') ++now;
        ans[i]=s[now++];
    }
    puts(ans+1);

    return 0;
}/*
102012012
*/

C.Annoying Present

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define eps 1e-8
typedef long long LL;
const int N=1e5+7;

inline int read()
{
    register int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}

int main()
{
    int n=read(), m=read();
    LL sum=0, sumX=0, C1, C2=1ll*n*(n-1)>>1;//n/2写成n>>1略显乱 
    if(n&1) C1=1ll*(n>>1)*((n>>1)+1);
    else C1=1ll*(n>>1)*((n>>1)+1)-1ll*(n>>1);
    LL x,d;
    for(int i=1; i<=m; ++i)
    {
        x=read(), d=read(), sumX+=x;
        if(d>0) sum+=C2*d;
        else if(d<0) sum+=C1*d;
    }
    printf("%.8lf",1.0*(sum+1ll*n*sumX)/n);

    return 0;
}

D.Relatively Prime Graph

靠 欺负我读英文题目不仔细吗 图必须连通。。
于是WA*3。看了数据才A。。
这破题 rank1000+了啊啊啊

而且这题n^2纯暴力都能过 太没意思了吧

#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define pr std::pair<int,int>
#define mp std::make_pair
const int N=1e5+7;

int n,m,cnt,P[N],fac[N],sum;
pr A[3000005];
bool not_P[N];

int gcd(int x,int y){
    return y?gcd(y,x%y):x;
}
void Pre(int n)
{
    for(int i=2; i<=n; ++i)
    {
        if(!not_P[i]) P[++cnt]=i;
        for(int j=1; j<=cnt&&i*P[j]<=n; ++j)
        {
            not_P[i*P[j]]=1;
            if(!(i%P[j])) break;
        }
    }
    for(int i=2; i<=n; ++i)
        if(!not_P[i]) fac[i]=i;
        else{
            for(int j=2; j<=i; ++j)
                if(!(i%j)) {fac[i]=j; break;}
        }
}

int main()
{
    scanf("%d%d",&n,&m);// printf("%d\n",m);
    if(m<n-1) return puts("Impossible"),0;//...
    Pre(n);
    for(int i=2; i<=n && sum<m; ++i) A[++sum]=mp(1,i);
    for(int x=1; x<=cnt && sum<m; ++x)
    {
        int i=P[x];
        for(int j=i+1; j<=n && sum<m; )
        {
            int k=std::min(j+fac[i]-1,n+1);//n+1!
            for(int l=j; l<k && sum<m; ++l) A[++sum]=mp(i,l);
            j=k+1;
        }
    }
    for(int i=4; i<=n && sum<m; ++i)
    {
        if(!not_P[i]) continue;
        for(int j=i+1; j<=n && sum<m; )
        {
            int k=std::min(j+fac[i]-1,n+1);
            for(int l=j; l<k && sum<m; ++l)
                if(gcd(i,l)==1) A[++sum]=mp(i,l);
            j=k+1;
        }
    }
    if(sum<m) puts("Impossible");
    else
    {
        puts("Possible");
        for(int i=1; i<=m; ++i)
            printf("%d %d\n",A[i].first,A[i].second);
    }

    return 0;
}

比赛结束后

E.Intercity Travelling(递推)

\(Description\)

  Leha从0出发前往n。给定数组\(a[]\)。路上可能会有一些休息点,Leha会在这些地方停下休息。如果当前所在休息点\(i\),而上一个休息点是\(j\),那他会得到\(a_{i-j}\)的困难值(包括在n点停下也要计算,路程上所有累加)。休息点一共有\(2^{n-1}\)种可能分布,求所有可能中整段路程所得到的困难值的期望\(e\times 2^{n-1}\mod\ 998244353\)

\(Solution\)

  要求一个线性做法,我们尝试递推求它。
  对每一个位置\(i\),我们可以写出它作为休息点时得到困难值的期望:\(e_i=\frac{a_1}{2}+\frac{a_2}{2^2}+\ldots+\frac{a_{i-1}}{2^{i-1}}+\frac{a_i}{2^{i-1}}\)。最后一项的概率是\(2^{i-1}\),因为是从0号点出发。
  那么就可以得到\(e_1=a_1,e_{i+1}=e_i-\frac{a_i}{2^i}+\frac{a_{i+1}}{2^i}\)

//93ms  7700KB
#include <cstdio>
#include <cctype>
#define gc() getchar()
#define mod (998244353)
const int N=1e6+5;

int n,A[N],pw[N];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}

int main()
{
    n=read();
    for(int i=1; i<=n; ++i) A[i]=read();
    pw[0]=1;
    for(int i=1; i<=n; ++i) pw[i]=pw[i-1]<<1, pw[i]>=mod&&(pw[i]-=mod);

    long long now=1ll*A[1]*pw[n-1]%mod, ans=now;
    for(int i=1; i<n; ++i)
    {
        now=(now-1ll*A[i]*pw[n-1-i]%mod+1ll*A[i+1]*pw[n-1-i]%mod+mod)%mod,
        ans+=now;
    }
    printf("%I64d\n",ans%mod);

    return 0;
}

F.Dominant Indices(启发式合并)

显然对于\(d_{x,i}\),我们有\(d_{x,i}=\sum_{v=son[x]}d_{v,i-1}\)
Dominant Indices就是最大的\(d_{x,i}\)中下标最小的\(i\)。我们可以利用启发式合并求\(d_x\)。启发式合并一般的复杂度是\(O(n\log n)\)的,但在本题中,复杂度只与深度较小的点的深度有关,而不是点数。所以复杂度是\(O(n)\)的。
我们还需要将数组整体右移,以便插入一个\(d_{x,0}=1\)。可以用map(\(O(n\log n)\)),也可以用vector倒序存储,这样就是\(O(n)\)的了。
也可以直接用个大点的(\(O(n)\)其实就够了)数组,每个点维护在数组中的位置。

[Update]这就是dsu on tree或者长链剖分啊。

//546ms 89700KB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const int N=1e6+5;

int n,Enum,H[N],nxt[N<<1],to[N<<1],Ans[N],A[N],pos[N],len[N],mx[N],mxpos[N];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
inline void AddEdge(int u,int v)
{
    to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
    to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void Merge(int x,int y)//x<-y
{
    if(len[x]<len[y])
    {
        std::swap(pos[x],pos[y]), std::swap(len[x],len[y]), 
        std::swap(mx[x],mx[y]), std::swap(mxpos[x],mxpos[y]);
    }
    for(int i=0,ly=len[y],px=pos[x],py=pos[y]; i<ly; ++i)
    {
        A[px+i]+=A[py+i]; //A[px+i+1]+=A[py+i];
        if(A[px+i]>mx[x]) mx[x]=A[px+i], mxpos[x]=i;
        else if(A[px+i]==mx[x] && i<mxpos[x]) mxpos[x]=i;
    }
}
void DFS(int x,int f)
{
    A[pos[x]]=1, len[x]=1, mx[x]=1, mxpos[x]=0;
    for(int v,i=H[x]; i; i=nxt[i])
        if((v=to[i])!=f)
        {
            pos[v]=pos[x]+len[x]+1, DFS(v,x);//给v腾出一位,合并前将v右移一位。否则len[x]==len[v]时会重叠。。
            A[--pos[v]]=0, ++len[v], ++mxpos[v], Merge(x,v);
        }
    Ans[x]=mxpos[x];
}

int main()
{
    n=read();
    for(int i=1; i<n; ++i) AddEdge(read(),read());
    pos[1]=1, DFS(1,1);
    for(int i=1; i<=n; ++i) printf("%d\n",Ans[i]);

    return 0;
}

G.Allowed Letters(Hall定理 位运算)

\(Description\)

给定长为n、由小写字母a~f组成的字符串s。有m个限制,每个限制为:在\(pos_i\)处只能是某些字母(\(pos_i\)两两不同)。
你可以任意交换原串两个字母的位置,问是否能得到满足限制的串,若能,输出满足限制的最小字典序的字符串。

\(Solution\)

有n个字符,每个字符可以放在某些位置,要求这些字符全部放置->完备匹配。
可以跑网络流,检查最大流是否等于n,连边比较好想。然后假设想要让i位置放字符c,如果原最大流不需要c->i这条边,那么可以;否则让这条边退流,容量-1,再检查最大流是否等于n。
如果决定了位置i放字符c,那么要使c->i这条边的容量-1.
没写,万一调不出来有点。。Tutorial里说复杂度\(O(n*2^A*A^2)\)(A为字符集大小),不知道\(2^A\)是为什么。。(好像也是判子集合法?)

可以考虑Hall定理。对于任意一个字符的子集,其中字符个数要<=能够匹配其中字符的位置个数。
这样的话对于同一种字符,显然只需要检验包含它最多的子集(位置数不会变)。所以我们要检查的子集只有\(2^A=64\)个(A为字符集大小)。
任意子集包含字符的个数sum可以\(O(A*2^A)\)\(O(2^A)\)算。对于(只要)能够匹配某子集s中任意字符 的位置数我们可以去算:位置总数-只能匹配除s中字符外的位置数。
除s中字符外的子集可以表示为2^A-1-s,预处理其包含的所有子集的位置数即可,记为f[]。
如果现在要确定i位置放什么,那要先减掉i对f的贡献,即枚举所有包括 位置i可放字符子集 的子集,依次-1。要放某字符首先要能放,然后数量-1,再Check就行了。

//62ms  400KB
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
#define lb(i) (i&-i)
const int N=1e5+7;

int n,num[7],can[N],sum[69],f[69],bit[69];
char s[N],tmp[N];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
bool Check()
{
    for(int i=1; i<64; ++i)
    {
        sum[i]=sum[i^lb(i)]+num[bit[lb(i)]];
        if(sum[i]>f[63]/*not n,or n也-1*/-f[63-i]) return 0;
    }
    return 1;
}

int main()
{
    scanf("%s",s+1), n=strlen(s+1);
    for(int i=1; i<=n; ++i) can[i]=63, ++num[s[i]-'a'];
    for(int m=read(),p; m--; )
    {
        can[p=read()]=0, scanf("%s",tmp+1);
        for(int j=1,l=strlen(tmp+1); j<=l; ++j)
            can[p]|=1<<tmp[j]-'a';
    }
    for(int i=1; i<=n; ++i) ++f[can[i]];
    for(int i=0; i<6; ++i)//求其包含的所有子集 先枚举i!
        for(int j=1; j<64; ++j)
            if(j>>i & 1)
                f[j]+=f[j^(1<<i)];
    for(int i=0; i<6; ++i) bit[1<<i]=i;
    if(!Check()) return puts("Impossible"),0;
    for(int i=1; i<=n; ++i)
    {
        for(int s=can[i]; s<=63; s=(s+1)|can[i]) --f[s];
        for(int j=0; j<6; ++j)
        {
            if(!(can[i]>>j&1)) continue;
            --num[j];
            if(Check()) {putchar(j+'a'); break;}
            ++num[j];
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/SovietPower/p/9311498.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值