Codeforces Round #553 (Div. 2) 题解

24 篇文章 0 订阅
19 篇文章 0 订阅

题目链接:http://codeforces.com/contest/1151

 

A. Maxim and Biology

暴力每个做起点即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e2 + 10;
char s[mx]; 
int main(){
	int n,ans = 1e9;
	scanf("%d%s",&n,s);
	for(int i=0;i<=n-4;i++){
		int a = abs(s[i]-'A');
		a = min(a,26-a);
		int b = abs(s[i+1]-'C');
		b = min(b,26-b);
		int c = abs(s[i+2]-'T');
		c = min(c,26-c);
		int d = abs(s[i+3]-'G');
		d = min(d,26-d);
		ans = min(ans,a+b+c+d);
 	}
 	printf("%d\n",ans);
	return 0;
} 

B. Dima and a Bad XOR

枚举一个二进制位数,看是否在每个行选择一个数,使得这个二进制位最后是1。那么很显然如果有一行对一个二进制位数的贡献既可以是1也可以是0,那么n行组成的对该二进制位数的贡献肯定可以是奇数。

还有就是一个细节问题,看代码就清楚了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 5e2 + 10;
int n,m,a[mx][mx],ans[mx];
bool vis[mx];
int find(int x,int d,bool f){
	for(int i=1;i<=m;i++){
		bool ok = a[x][i]&(1<<d);
		if(f==ok) return i;
	}
}
void solve(){
	for(int i=0;i<10;i++){
		int d = 0;bool w = 0;
		memset(vis,0,sizeof(vis));
		for(int j=1;j<=n;j++){
			int c = 0;
			for(int k=1;k<=m;k++){
				if(a[j][k]&(1<<i))
				c++;
			}
			if(c==m) d++;
			if(c&&c!=m) w = vis[j] = 1;
		}
		if((d&1)||w){
			puts("TAK");
			bool f = !(d&1);
			for(int j=1;j<=n;j++){
				if(!vis[j]) printf("1 ");
				else printf("%d ",find(j,i,f)),f=0;
			}
			return;
		}
	}
	puts("NIE");
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)
		scanf("%d",a[i]+j);
	}
	solve();
	return 0;
} 

C. Problem for Nazar

这题其实也不难,按照题目说的做,然后二进制倍增+等差数列求和就是了。注意一点点细节就好了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 5e2 + 10;
const int mod = 1e9 + 7;
ll l,r,siz[2];
bool vis[mx];
void add(ll &ans,ll len,ll c,int b){
	b ^= 1;
	len %=mod,c %= mod;
	ans += ((2*c-(1<<b))*len%mod+len*len%mod);
	ans %= mod;
}
int main(){
	scanf("%lld%lld",&l,&r);
	int bit = 0;
	ll p = 0,c,len,ans = 0;
	while(p+(1ll<<bit)<l){
		p += (1ll<<bit);
		siz[bit&1] += (1ll<<bit);
		bit++;
	}
	if(p+(1ll<<bit)>=r){
		len = (r-l+1);
		c = (siz[bit&1]+l-p);
		add(ans,len,c,bit&1);
		printf("%lld\n",ans%mod);
		return 0;
	}
	len = (1ll<<bit)-(l-p)+1;
	c = (siz[bit&1]+l-p);
	add(ans,len,c,bit&1);
	p += (1ll<<bit),siz[bit&1] += (1ll<<bit),bit++; 
	while(p+(1ll<<bit)<r){
		add(ans,1ll<<bit,siz[bit&1]+1,bit&1);
		p += (1ll<<bit);
		siz[bit&1] += (1ll<<bit);
		bit++;
	}
	len = r - p;c = siz[bit&1] + 1;
	add(ans,len,c,bit&1);
	printf("%lld\n",ans); 
	return 0;
} 

D. Stas and the Queue at the Buffet

这题我感觉放在D不是那么合适,化一个公式然后排序贪心就ok了。

将原式ai⋅(j−1)+bi⋅(n−j) 化为 (ai-bi) *j - ai + bi*n。然后发现后面两个式子是和j没有关系的,直接求出。

对于第一个式子,把ai-bi看做整体,排个序,值大的占小头,值小的占大头,就可以保证最小值啦。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e5 + 10;
const int mod = 1e9 + 7;
int n,c[mx]; 
int main(){
	scanf("%d",&n);
	ll ans = 0;
	int a,b;
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a,&b);
		ans += 1ll*b*n - a;
		c[i] = a - b;
	}
	sort(c+1,c+1+n);
	for(int i=1;i<=n;i++) ans += 1ll*c[i]*(n-i+1);
	printf("%lld\n",ans);
	return 0;
} 

E. Number of Components

首先要做的是缩点,也就是对于相等的数连续的一块,缩成一个点,显然对结果是不影响的。接下来我们再具体分析。

如果i位置的值被留下:

1.i-1和i+1被留下,对于结果-> +1-2 = -1;

2.i-1被留下,对于结果 +1-1 = 0

3.i+1被留下,对于结果 +1-1 = 0 

3.i+1和i-1都没有被留下,对于结果 +1。

因此,我们可以看做每个点i的初始贡献是1,如果它的相邻点也参与了贡献并且它的值小于a[i](防止被重复计算),那么就给i点另外加一个-1的贡献。计算i和他的相邻点是否同时贡献也就是计算他们的值是否都在区间中,这些都可以利用组合数轻松求出。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e5 + 10;
const int mod = 1e9 + 7;
int n,a[mx]; 
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",a+i);
	}
	int c = 1;
	for(int i=2;i<=n;i++){
		if(a[i]!=a[c]) a[++c] = a[i]; 
	}
	a[c+1] = a[0] = n+1;
	ll ans = 0;
	for(int i=1;i<=c;i++){
		ans += 1ll*a[i]*(n-a[i]+1);
		if(a[i-1]<a[i]){
			ans -= 1ll*a[i-1]*(n-a[i]+1);
		}
		if(a[i+1]<a[i]){
			ans -= 1ll*a[i+1]*(n-a[i]+1);
		}
	}
	printf("%lld\n",ans);
	return 0;
} 

F. Sonya and Informatics

假设n个数中0有c个,1有d个,c+d = n。最后的结果肯定是钱c个数要是0,后d个数要是1。

那么我们就可以考虑一个转态f[i][j],表示交换了j次之后,前c个数中有i个数是1的方案数。

很明显f[i][j]可以转移到:f[i][j+1],f[i-1][j+1],f[i+1][j+1]

但是我们发现j过于大,不可能这么维护一个二维数组,所以取考虑一个矩阵快速幂,这样就可以把第二维去掉了,而且我们发现第一维的大小最多是min(c,d)<=50。

所以最后时间复杂度可以做到O(50^{3}*log(K))

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e2 + 10;
const int mod = 1e9 + 7;
const int N = 50;
int n,a[mx],K; 
struct node
{
	int mat[55][55];
}base;
node matr(node &p1,node &p2)
{
	node ret;
	memset(&ret,0,sizeof(node));
	for(int k=0;k<=N;k++){
		for(int i=0;i<=N;i++){
			if(p1.mat[i][k]);
			for(int j=0;j<=N;j++){
				ret.mat[i][j] += 1ll*p1.mat[i][k]*p2.mat[k][j]%mod;
				ret.mat[i][j] %= mod;
			}
		}
	}
	return ret;
}
node mpow(int y,int p){
	node ans;
	memset(&ans,0,sizeof(node));
	ans.mat[0][p] = 1;
	while(y){
		if(y&1) ans = matr(ans,base);
		base = matr(base,base);
		y >>= 1;
	}
	return ans;
}
ll qpow(ll x,ll y){
	ll ans = 1;
	while(y){
		if(y&1) ans = ans*x%mod;
		y >>= 1;
		x = x*x%mod;
	}
	return ans;
}
int main(){
	scanf("%d%d",&n,&K);
	int c = 0,d = 0,b = 0;
	for(int i=1;i<=n;i++){
		scanf("%d",a+i);
		if(a[i]) d++; else c++;
	}
	for(int i=1;i<=c;i++) if(a[i]) b++;
	base.mat[0][0] = c*(c-1) / 2 + d*(d-1) / 2;
	base.mat[1][0] = 1;
	for(int i=1;i<=min(c,d);i++){
		base.mat[i-1][i] = (c-i+1)*(d-i+1);
		base.mat[i][i] = c*(c-1) / 2 + d*(d-1) / 2;
		base.mat[i][i] += (c-i)*i + (d-i)*i;
		base.mat[i+1][i] = (i+1)*(i+1); 
	}
	ll ans = mpow(K,b).mat[0][0];
	printf("%lld\n",ans*qpow(qpow(n*(n-1)/2,K),mod-2)%mod);
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值