Codeforces Round #654 (Div. 2) 补题报告

A. Magical Sticks
给你n个木棍,可以任意拼接,问你最多能有多少个相同长度的,那肯定是1和n拼n+1,2和n-1拼n+1,以此类推

int T,n;
int main()
{
	cin>>T;
	while(T--)
	{
		cin>>n;
		//a+b=c
		//1+n=n+1
		//2+n-1=n+1
		cout<<(n+1)/2<<"\n";
	}
	return 0;
}

B. Magical Calendar
找不相等的排列
由于需要联通,所以当n>k的时候,肯定是联通的,随便摆,方案数是k,当n=k的时候,因为需要联通,只能在同一行,所以方案数是1,当n<k的时候,因为需要联通,同样只能在同一行,而既然在同一行了,长度又肯定是n,和n=k的时候排列重复了,都不用考虑了,所以最后的总方案数就是n>k的时候,k的总和,再加上n=k的时候的1

ll T,n,r;
int main()
{
	cin>>T;
	while(T--)
	{
		long long sum=0;
		cin>>n>>r;
//		rep(i,1,r+1)
//		for(ll i=1;i<=r;i++)
//		{
//			if(n>=i+1)
//			sum+=i;
//			else
//			{
//				sum+=i+1-n;
//				break;
//			}
//		}
		//1~n-1
		if(r>=n-1)
		sum+=n*(n-1)/2;
		else
		sum+=r*(r+1)/2;
		if(r>=n)
		sum+=1;
		cout<<sum<<"\n";
	}
	return 0;
	//n==k  1 
	//n=k+1 k
	//n>k+1 k
	//n=k-i i+1
	//n=1 k
	//n=0 0
	//k+1-n k->maxn 
}

C. A Cookie for You
2类客人,对物品取舍不同,第一类人假如v>c,优先选v的,第二类人却选c的,所以第二类人肯定比第一类人危险多了,毕竟他每次是优先选少的,万一那一堆是0就出事了
所以最好的方案肯定是先第一类人,把a,b里多的拿走,直到a=b,然后先第一类人,再第二类人,这样每次结束后a都保持等于b,然后分析啥时候n和m消耗完,没了,记得开longlong,一开始是int,wa 3了

ll T,a,b,n,m;
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		cin>>a>>b>>n>>m;
		if(a+b<n+m)
		{
			cout<<"No\n";
			continue;
		}
		//u==c 第二类 u--  then 第一类 c-- 变回去了  
		ll asd=abs(a-b);
		asd=min(asd,n);
		n-=asd;
		if(a>b)
		a-=asd;
		else
		b-=asd;
		if(n==0)
		{
			if(m<=min(a,b))
			{
				cout<<"Yes\n";
			}
			else
			cout<<"No\n";
		}
		else
		{//a==b
//			int qwe=abs(n-m);
			ll qwe=min(n,m);
			a=b=a-qwe;
			n-=qwe,m-=qwe;
			if(n==0)
			{
				if(m<=a)
				cout<<"Yes\n";
				else
				cout<<"No\n";
			}
			else
			{
				if(n<=a+b)
				cout<<"Yes\n";
				else
				cout<<"No\n";
			}
		}
	}
	return 0;
}

D. Grid-00100
一开始还以为要使f(A)尽量大,然后才发现是尽量小。。。
然后口胡了一个解法,就是每次斜着填格子,直到k=0,然后,然后就过了。。。

int T,a[400][400];
int n,k;
int main()
{
	cin>>T;
	while(T--)
	{
		ms(a);
		int cnt=1;
		cin>>n>>k;
		int i=1,j=1;
		while(k--)
		{
			a[i++][j++]=1;
			if(j>n)
			j=1;
			if(i==n+1)
			{
				i=1;
				j=++cnt;
			}
			//1 1 2 2  1 2 
		}
		int lmax=0,lmin=inf,cmax=0,cmin=inf;
		rep(i,1,n+1)
		{
			int sum=0,num=0;
			rep(j,1,n+1)
			{
				sum+=a[i][j];
				num+=a[j][i];
			}
			lmax=max(lmax,sum);
			lmin=min(lmin,sum);
			cmax=max(cmax,num);
			cmin=min(cmin,num);
		}
		cout<<(lmax-lmin)*(lmax-lmin)+(cmax-cmin)*(cmax-cmin);
		cout<<"\n";
		rep(i,1,n+1)
		{
			rep(j,1,n+1)
			cout<<a[i][j];
			cout<<"\n";
		}
	}
	return 0;
}

E1. Asterism (Easy Version)
E2. Asterism (Hard Version)
题意太难懂了。。。。读了10分钟我才发现一开始理解错了
大概意思就是枚举x的初始值,使得最后排序方案不得被p整除
那就先确定肯定被p整除的情况,首先肯定是没有方案的时候,设a[i]中最大值为maxx,那也就是n<maxx-n+1,这样无论怎么排序,最大值都无法取到,所以假如不被p整除,n至少得大于等于maxx-n+1,而我们又知道n>=p,所以假如n>=maxx,就是可以全排列了,方案数是 n ! n! n!的时候, n ! n! n!必然被p整除,所以n必然<maxx
所以有可能不被p整除时,n的范围在[maxx-n+1,maxx)之间
E1范围小,可以直接枚举,但E2范围大如何解决呢?
我们可以这么分析,假如a[i]放在i位置上,那他必然可以放在i+1,i+2,i+…,n位置上,因为后面的时候,x在不断+1,假如在i位置都可以保证x>=a[i],那么在后面更可以保证,所以我们可以预处理每个值有多少个a[i]可以小于等于此值,先把a数组sort一下,然后直接二分查找,设sum[i]为小于等于i的a[i]的数量,统计,然后就可以计算了,大概是这个式子
∏ i = x x + n − 1 x − ( i − s u m [ i ] ) \prod_{i=x}^{x+n-1}{x-(i-sum[i])} i=xx+n1x(isum[i]),i从x一直到n-1,一直叠乘,所以中间假如每次出现了能被p整除的,就可以直接break了,去找下一次的x了,而我们又发现 i − s u m [ i ] i-sum[i] isum[i]其实是固定的,所以我们而每次直接查 x x x i − s u m [ i ] i-sum[i] isum[i]是否关于p同余就行,所以我们直接把num[i]设为储存 i − s u m [ i ] i-sum[i] isum[i]对p的余数的数量,每次判断x的时候,直接查询相应的num[x%p]是否为0,为0的话意味着没有一个 i − s u m [ i ] i-sum[i] isum[i]跟此次的x同余,那就可行的,扔进vector数组,同时不管可行与否,因为x已经判断完毕,应该删除x的贡献,同时为了x+1的检验,加入x+n的贡献,做完了

vector<int> v1;
int n,p;
int a[maxn];
int num[maxn];
int main()
{
	cin>>n>>p;
	rep(i,1,n+1)
	cin>>a[i];
	sort(a+1,a+n+1);
//	rep(i,1,n+1)
//	{
//		s[i]=s[i-1]+a[i];
//	}
	rep(i,a[n]-n+1,a[n]+1)
	{
//		int asd=lower_bound(a+1,a+n+1,i)-a-1;
		int asd=upper_bound(a+1,a+n+1,i)-a-1;
		num[((i-asd)%p+p)%p]++;
//		if(num[i%p]==0)
//		v1.push_back(i);
//		num[asd]
	}
	rep(i,a[n]-n+1,a[n]+1)
	{
		if(num[(i%p+p)%p]==0)
		v1.push_back(i);
		int asd=upper_bound(a+1,a+n+1,i)-a-1;
		int qwe=upper_bound(a+1,a+n+1,i+n)-a-1;
		num[((i-asd)%p+p)%p]--;
		num[((i-qwe+n)%p+p)%p]++;
	}
	cout<<v1.size()<<"\n";
	for(int i:v1)
	{
		cout<<i<<" ";
	}
	cout<<"\n";
	return 0;
	
}
//赢了永久+1 
//全赢
//1.  x>= maxn a[i] n! %p==0
//2.  x<minn a[i] 0 

//3. x>=maxn-n+1  maxn放最后一位  

//4 .x< maxn-n+1 无解  %p==0
//maxn-n+1 ~ maxn 
//x>=a[i]-i+1

// x ~ x+n-1
// min  max 
//ti-(0~n-1)
//x-(i-ti) x x+n-1

F. Raging Thunder
2800的题呀,emmm,要不逃?
n个传送带,n+1个洞
有q次翻转操作
问你哪个洞里球会最多,输出这个数量
很标准的线段树的啦,直接建2个树,一个原本的,一个默认全部翻转,每次翻转[l,r]的时候就交换这2个树这2个区域的值
想法很简单,但是实际操作嘛,emmmm,就很繁琐了
先留着吧,过2天再补

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值