zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 47 (Div 2) (A~G)


    Codeforces 1009

    比赛链接

    hack好给力啊233

    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
    ",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
    ",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
    ",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 imes 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
    ",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(nlog n))的,但在本题中,复杂度只与深度较小的点的深度有关,而不是点数。所以复杂度是(O(n))的。
    我们还需要将数组整体右移,以便插入一个(d_{x,0}=1)。可以用map((O(nlog 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
    ",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;
    }
    
  • 相关阅读:
    16-hadoop-mapreduce简介
    centos7-windows10 双系统安装
    5.4 RDD编程---综合案例
    8.2 数据结构---字符串(查找)
    8.1 数据结构---字符串
    5.3 RDD编程---数据读写
    5.2 RDD编程---键值对RDD
    5.1 RDD编程
    4.Spark环境搭建和使用方法
    3.3 Spark的部署和应用方式
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9311498.html
Copyright © 2011-2022 走看看