zoukankan      html  css  js  c++  java
  • Codeforces Round #747 (Div. 2)题解

    谢天谢地,还好没掉分,还加了8分,(8分再小也是加啊)前期刚开始有点卡,不过在尽力的调整状态之后,还是顺利的将前面的水题过完了,剩下的E2和F题就过不去了,估计是能力问题,自己还是得认真补题啦。

    E2. Rubik's Cube Coloring (hard version)

    这个题是在上一题的基础上出现的,E1的就很简单,一个完全二叉树,每个点都没有染色,求不同染色方案的方案数。显然的是在第一个点的颜色确定后,后面所有点的颜色都只有4种选择,也就是无论父节点选了什么颜色,该节点都有且仅有四种选择。所以答案就是(6*4^{n-1}).那么作为困难版的,这个题就是给某些点已经染上了颜色,要求所有的方案数。显然上一题的简单思路不能解决这个题了,因为我们似乎不能将所有的点都割裂开了。考虑这个例子,一个节点的父节点和子节点都以前提前被染过色了,那么该节点的颜色选择就依赖于父节点和子节点的颜色。像这种题,肯定存在一些性质,或者说我们没有找到颜色之间限制的本质。考虑这样一个事情,就像简单题的那个例子,若一颗树,其根节点确定后,那么颜色的方案数就是(4^{n-1}),那么考虑在有一些点被提前确定颜色的树上,我们能不能用上这个结论,我们先找到这棵树上的所有符合条件子树,他们的所有节点都没有被确定颜色。那么对于这些节点,他们的根节点的颜色可能有限制,但他们非根节点的颜色方案数就是4,我们用最朴素的思路,采取dp的思路,某些点上必须采用dp的方式才能解决颜色限制的问题,但有些子树,所有节点都没被提前染色,他们的方案数就能快速计算。观察题目数据,有颜色的点是(2000),考虑一个有颜色的点最多使多少个点必须用dp的方式,显然是n,那么总的dp的状态数就是(2000*60*6*3)如果采用map的话,还需要多乘一个log。
    (我死也没想到我会死在快速幂上,以后的(y)我都打成(long long)....)

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int P=1e9+7;
    int n,k;
    char c[10];
    map<ll,int>vis,co,f[4];
    
    inline ll power(ll x,ll y)
    {
    	ll ans=1;
    	while(y)
    	{
    		if(y&1) ans=ans*x%P;
    		y>>=1;
    		x=x*x%P;
    	}
    	return ans%P;
    }
    
    inline void dfs(ll x,int dep)
    {
    	if(dep>n) return;
    	if(vis.find(x*2)!=vis.end()) dfs(x*2,dep+1);
    	if(vis.find(x*2+1)!=vis.end()) dfs(x*2+1,dep+1);
    	if(co.find(x)!=co.end()) f[co[x]][x]=1;
    	else f[1][x]=f[2][x]=f[3][x]=2;
    	if(dep==n) return;
    	ll F[4],G[4],C[4]={0,0,0,0};//分别表示两个儿子不同颜色的方案数。
    	ll ds=(2ll*power(4,(1ll<<(n-dep))-2))%P;
    	if(vis.find(2*x)!=vis.end())
    		for(int i=1;i<=3;++i) F[i]=f[i][2*x];
    	else 
    		for(int i=1;i<=3;++i) F[i]=ds;
    	if(vis.find(2*x+1)!=vis.end())
    		for(int i=1;i<=3;++i) G[i]=f[i][2*x+1];
    	else 
    		for(int i=1;i<=3;++i) G[i]=ds;
    	C[1]=(F[2]*G[2]%P+F[2]*G[3]%P+F[3]*G[2]%P+F[3]*G[3]%P)%P;
    	C[2]=(F[1]*G[1]%P+F[1]*G[3]%P+F[3]*G[1]%P+F[3]*G[3])%P;
    	C[3]=(F[1]*G[1]%P+F[1]*G[2]%P+F[2]*G[1]%P+F[2]*G[2])%P;
    	for(int i=1;i<=3;++i) f[i][x]=C[i]*f[i][x]%P;		
    } 
    
    int main()
    {
    	//freopen("1.in","r",stdin);
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=k;++i)
    	{
    		ll id;scanf("%lld",&id);
    		scanf("%s",c+1);
    		if(c[1]=='w'||c[1]=='y') co[id]=1;
    		else if(c[1]=='g'||c[1]=='b') co[id]=2;
    		else if(c[1]=='r'||c[1]=='o') co[id]=3;
    		while(id)
    		{
    			vis[id]=1;//标记这些点不能直接算。
    			id=id/2; 
    		}
    	}
    	dfs(1,1);
    	int ans=((f[1][1]+f[2][1])%P+f[3][1])%P;
    	printf("%d",ans);
    	return 0;
    } 
    

    F. Ideal Farm

    这个数学题真的屯了好久....淦!
    首先我们定义(a_i)为每个围栏的牛的个数,则(a_i)>=1,题目要求无论怎么分,都必须有一个连续的区间使得这个区间内的(a_i)的和为k。第一部,我们定义pre[i]为a[i]的前缀和,为什么呢?方便区间和的运算。其中pre[0]=0,pre[n]=s,那么题目就变成了我们能否构造一个序列使得不存在pre[i]-pre[j]=k.((0leq j<ileq n)).由于(a[i])都是正整数,所以pre是递增的且各不相同。之后考虑怎么构造a数组是比较麻烦,相比较下,我们考虑怎么构造pre数组,由于pre的性质,其实我们要做的就是在(0,s)中选出n-1个数(因为pre[n]一定是s),使得他们作为当前的pre数组。并且保证不能存在两个被选择的数作差为k。作差为k,我们很容易想到同余系,只有当两个数对k同余时,他们作差才可能为k。既然如此,那我们大可以按照k的余数将(0,s)中的数进行分类。
    首先因为pre[0]=0,pre[n]=s,我们先对这两个同余系进行讨论,(先假设s=p*k+r((0leq rleq k-1)))先考虑pre[0],它的同余系中的所有数有:(0,k,2k,3k,...),发现在(0,s)中一共有(lfloor frac{s}{k} floor)+1个,由于0已经选过了,且k不能选,所以我们最多拿(lceilfrac{lfloor frac{s}{k} floor-1}{2} ceil).同理,对于r的同余系而言,所有数为(r,k+r,2*k+4...,p*k+r),一共(lfloorfrac{(s-r)}{k} floor+1=lfloorfrac{s}{k} floor+1),同理(p*k+r,和(p-1)*k+r)我们同样不能选,故我们能选的个数为(lceilfrac{lfloorfrac{s}{k} floor-1}{2} ceil),对于其他的余数((1leq xleq k-1且x!=r)),我们都有x,x+k,...总的个数都为(lfloorfrac{s-x}{k} floor+1),我们能选出的个数为(lceilfrac{lfloorfrac{s-x}{k} floor+1}{2} ceil)所以总的能选出来的个数为:(2 imeslceilfrac{lfloor frac{s}{k} floor-1}{2} ceil+sum_{x=1}^{k-1}lceilfrac{lfloorfrac{s-x}{k} floor+1}{2} ceil(x!=r))在求和号中,k依然比较大,因为(s=p*k+r),当(x<r)时,可取(lceilfrac{p+1}{2} ceil(x!=r)),当(x>r)时,可取(lceilfrac{p}{2} ceil(x!=r))所以我们最后的答案就是(ans=2 imeslceilfrac{lfloor frac{s}{k} floor-1}{2} ceil+(r-1)*lceilfrac{p+1}{2} ceil+(k-1-r)*lceilfrac{p}{2} ceil)。但考虑一种情况,即r=0的情况,观察我们上述式子,会发现上述推论可能存在一些问题,但我们观察我们的式子,能否得到正确的答案。如果你有兴趣的话1,你话发现结果是一样的,滑稽,这里就不给出详细的推导过程了,留作思考吧。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    int T;
    int main()
    {
    //	freopen("1.in","r",stdin);
    	scanf("%d",&T);
    	while(T--)
    	{
    		ll s,n,k;
    		scanf("%lld%lld%lld",&s,&n,&k);
    		if(s<k) puts("NO");
    		else if(s==k) puts("YES");
    		else
    		{
    			ll p=s/k,r=s%k;
    			ll ans=2ll*ceil((p-1)/2.0)+(r-1)*ceil((p+1)/2.0)+(k-1-r)*ceil(p/2.0);
    			if(ans>=n-1) puts("NO");
    			else puts("YES"); 
    		}
    	}
    	return 0;
    } 
    
  • 相关阅读:
    LightOJ1074(spfa+dfs标记负环及负环能够到达的点)
    (模板)AC自动机模板
    poj3660(floyd最短路)
    (模板)hdoj2544(最短路--bellman-ford算法&&spfa算法)
    hdoj4099(字典树+高精度)
    poj1056(字符串判断是否存在一个字符串是另一个字符串的前缀)
    hdoj1247(字典树)
    poj3630||hdoj1671(字典树)
    (模板)hdoj1251(字典树模板题)
    poj3348(求凸包面积)
  • 原文地址:https://www.cnblogs.com/gcfer/p/15387332.html
Copyright © 2011-2022 走看看