Codeforces round 419 div2 补题 CF 816 A-E

Karen and Morning

水题 注意进位即可

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
 int a,b;
bool pal()
{
 if((a%10)==(b/10)&&(a/10)==(b%10))return true;
 	else return false;
}

void add()
{
 b+=1;
 while(b>=60)b-=60,a+=1;
 while(a>=24)a-=24;
}
int main()
{
 char c;
 scanf("%d%c%d",&a,&c,&b);
 int ans=0;
 while(!pal())
 	{
 	 add();
 	 ans++;
	 }
 printf("%d\n",ans);
 return 0;
}

  

Karen and Coffee

用线段树维护是显而易见的

不过由于先添加了所有点才进行所有询问,也就是说不会动态改变数据 所以用线段树是大材小用了。

用线性的方法也可以维护 这里只给出线段树代码。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e7,R=200000;
int size[N],adn[N],n,k,q;
vector<int>num;
void pushdown(int cur)
{
 adn[cur*2]+=adn[cur];
 adn[cur*2+1]+=adn[cur];
 adn[cur]=0;
}
void add(int cur,int ln,int rn,int l,int r)
{
 if(l<=ln&&r>=rn){adn[cur]++;return ;}
 int mid=(ln+rn)>>1;
 pushdown(cur);
 if(l<=mid)add(cur*2,ln,mid,l,min(mid,r));
 if(r>mid)add(cur*2+1,mid+1,rn,max(mid+1,l),r);
}

void update(int cur,int ln,int rn)
{
 if(ln==rn)
 	{
 	 if(adn[cur]>=k)size[cur]=1;
 	 	else size[cur]=0;
 	 return ;
	}
 pushdown(cur);
 int mid=(ln+rn)>>1;
 update(cur*2,ln,mid);
 update(cur*2+1,mid+1,rn);
 size[cur]=size[cur*2]+size[cur*2+1];
}

void que(int cur,int ln,int rn,int l,int r,int& anss)
{
	if(l<=ln&&r>=rn){anss+=size[cur];return ;}
	int mid=(ln+rn)>>1;
	if(l<=mid)que(cur*2,ln,mid,l,min(mid,r),anss);
	if(r>mid)que(cur*2+1,mid+1,rn,max(l,mid+1),r,anss);
}
int main()
{//freopen("t.txt","r",stdin);
 scanf("%d%d%d",&n,&k,&q);
  int l,r;
 for(int i=0;i<n;i++)
 	{
 	 scanf("%d%d",&l,&r);
 	 add(1,1,R,l,r);
	}
 update(1,1,R);
 for(int i=0;i<q;i++)
 	{
 	 int anss=0;
 	 scanf("%d%d",&l,&r);
 	 que(1,1,R,l,r,anss);
 	 printf("%d\n",anss);
	}
 return 0;
}

C Karen and Game

很简单的贪心。。放在C的位置有点过于简单了吧(虽然我被Hack了 不过是打字失误。。mdzz)

提交前还是应该一行一行过一遍。。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=200;
int num[N][N];
int n,m;
vector<int>co,ro;
int suma,sumb;
void row()
{
 for(int i=0;i<n;i++)
 	{
     int miv=num[i][0];
	 for(int j=1;j<m;j++)
	 	miv=min(miv,num[i][j]);
	 for(int j=0;j<m;j++)
	 	num[i][j]-=miv;	
	 sumb+=miv*m;
	 for(int k=0;k<miv;k++)
	 	ro.push_back(i);
	}
}
void col()
{
 for(int i=0;i<m;i++)
 	{
     int miv=num[0][i];
	 for(int j=1;j<n;j++)
	 	miv=min(miv,num[j][i]);
	 for(int j=0;j<n;j++)
	 	num[j][i]-=miv;	
	 sumb+=miv*n;
	 for(int k=0;k<miv;k++)
	 	co.push_back(i);
	}
}

int main()
{//freopen("t.txt","r",stdin);
 scanf("%d%d",&n,&m);
 for(int i=0;i<n;i++)
 	for(int j=0;j<m;j++)
 		scanf("%d",&num[i][j]),suma+=num[i][j];
 if(n>m){col();row();}
 	else {row();col();}
 if(suma!=sumb){printf("-1\n");return 0;}
 printf("%d\n",(int)ro.size()+(int)co.size());
 for(int i=0;i<ro.size();i++)
 	printf("row %d\n",ro[i]+1);
 for(int i=0;i<co.size();i++)
 	printf("col %d\n",co[i]+1);
 return 0;
}

  

D Karen and Test

技巧性很强的一道计数题 我们考虑计算每个数对答案的贡献 即它的系数

观察发现 某个数的系数c 是它下一行的相邻两个数的系数的线性组合 是不是有点像组合数C(n,m)的递推公式 C(n,m)=C(n-1,m-1)+C(n-1,m)

我们大胆猜测该系数是某种组合数的形式

运用归纳法发现了公式

 

另外发现了一个特点,当n=4k+1时 第一次进行加法和第一次进行减法的结果是相同的!(也可以用归纳法证明)

所以,对于输入数据,我们首先进行几次暴力运算,将它转化为n=4k+1的形式 之后我们套用系数公式即可。

做计数问题真的是要大胆猜想啊!!! 这道题猜到是组合数就离答案很近了!

#include <bits/stdc++.h>
#define MAXN 200010
using namespace std;
const int mod=1e9+7;
int n,a[MAXN];

long long q_pow(long long x,long long n)
{
	long long res=1,tmp=x;
	while(n){
		if(n&1) res=res*tmp%mod;
		tmp=tmp*tmp%mod;
		n>>=1;
	}
	return res;
}

int main()
{
	int i,j,c=1;
	scanf("%d",&n);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	while(n%4!=1){
		for(i=1;i<n;i++){
			if(c) a[i]=(a[i]+a[i+1])%mod;
			else a[i]=(a[i]-a[i+1]+mod)%mod;
			c^=1;
		}
		n--;
	}
	long long p=n/2,C=1,ans=0;
	for(i=0;i<=p;i++){
		if(i) C=C*(p-i+1)%mod*q_pow(i,mod-2)%mod;
		//cout<<C<<endl;
		ans+=C*a[i<<1|1];
		ans%=mod;
	}
	cout<<ans<<endl;
 return 0;
}

 补充证明一下:为什么当n=4k+1时有很好的性质呢? 比如n=5的三角形题目也给出了 那么当n=4*2+1=9时 实际上是由5个n=5时的三角形部分重叠构成的!

    在这个基础上 所有的归纳证明都好办了。

E Karen and Supermarket 

很有趣的一道树形DP 题目给我们的所有商品显然构成了以商品1为根的树

我们首先转化问题 考虑买j个商品的最小花费,然后枚举判断即可。

那么 我们设函数f[i][j]表示 在子树i中购买j个商品可以使用优惠券的最小花费(即保证购买了商品i且使用了i的优惠券)

 g[i][j] 表示在子树i中购买j个商品不可以使用优惠券的最小花费

转移方法是比较简单的,对于当前节点i 每次添加一个它的儿子(子树),枚举在新的子树中购买k个商品,在之前添加的所有子树中购买j-k个商品即可。

__________________________________________________________________________________

 

那么问题来了 这个转移的复杂度到底是多少? 

先说结论,看似总的是三层循环,应该是O(n^3)实际复杂度是O(n^2)

为什么呢? 这里采用反证法证明

假如三层循环的上界都是 关于n的一次函数(不妨设 an,bn,cn) 此时满足总的复杂度O(n^3)

但是,由于最外层循环添加了 an个子树(a是任意正实数 满足an为整数) 最内层循环每次添加了cn个节点

即有an个子树,且存在一个子树有cn个节点,那么总的节点数就成了acn^2  意味着节点数不是O(n)而是O(n^2)出现矛盾

所以三层循环不可能出现每层循环的上界都为n的一次函数的情况 即复杂度是n^3的无穷小。那么其幂函数部分必然是O(n^2)

#include<bits/stdc++.h>
#include<vector>
#define N 5005
using namespace std;
const int oo=(1<<30)-1;
vector<int> G[N];
int n,m,sz[N],a[N],b[N],f[N][N],g[N][N],h[N];
void dfs(int t)
{
	int i,j,k,x; sz[t]=1;
	for(i=1;i<=n;i++) f[t][i]=g[t][i]=oo;
	f[t][1]=a[t]-b[t];
	g[t][0]=0,g[t][1]=a[t];
	for(i=0;i<G[t].size();i++){
		dfs(x=G[t][i]);
		for(j=1;j<=sz[t];j++) h[j]=f[t][j];
		for(j=1;j<=sz[t];j++)
			for(k=1;k<=sz[x];k++)
				f[t][j+k]=min(f[t][j+k],h[j]+min(f[x][k],g[x][k]));
		for(j=0;j<=sz[t];j++) h[j]=g[t][j];
		for(j=0;j<=sz[t];j++)
			for(k=1;k<=sz[x];k++)
				g[t][j+k]=min(g[t][j+k],h[j]+g[x][k]);
		sz[t]+=sz[x];
	  }
}
int main()
{
	int i,x;
	scanf("%d %d",&n,&m);
	for(i=1;i<=n;i++){
		scanf("%d %d",&a[i],&b[i]);
		if(i>1) scanf("%d",&x),G[x].push_back(i);
	  }
	dfs(1);
	for(i=1;i<=n;i++)
		if(min(f[1][i],g[1][i])>m) break;
	cout<<i-1;
	return 0;
}

  

蛤蛤 这个复杂度分析是不是很有趣? 看代码吧

 

转载于:https://www.cnblogs.com/heisenberg-/p/7043093.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值