Codeforces Round #674 (Div. 3)

A.Floor Number
对于第一层要分开来算;当不整除时注意加一。
#include <bits/stdc++.h>
using namespace std;

int T;
int n,x,ans;
int main(){
	scanf("%d",&T);
	while (T--)
	{
		scanf("%d%d",&n,&x);
		n-=2; ans=1;
		if (n<=0)
		{
			printf("%d\n",ans);
			continue;
		}
		if (n%x==0) ans+=n/x;
		else ans+=n/x+1;
		printf("%d\n",ans);
	}
return 0;	
}
B.Symmetric Matrix
只要有一个正方形满足:b=c即可。
#include <bits/stdc++.h>
using namespace std;

int T;
int n,m,a,b,c,d;
int main(){
	scanf("%d",&T);
	while (T--)
	{
		scanf("%d%d",&n,&m);
		bool jay=false;
		for (register int i=1; i<=n; ++i) 
		{
			scanf("%d%d%d%d",&a,&b,&c,&d);
			if (b==c) jay=true;	
		}
		if (m%2==1) {puts("NO"); continue;}
		if (jay) puts("YES");
		else puts("NO");
	}
return 0;	
}
C. Increase and Copy
我们来考虑一下最后的若干个数的最优形式:假设现在我们经过a-1次操作,构造出了一个a,那么我们现在想得到一个b,设(b>a),所以我们现在需要1+(b-a)次变化,可以得到数列:ab。 (先复制一次a,然后将那个复制的a操作b-a次变成b)
那么如果我直接将a操作b-a次变成b,然后再复制一次b,那么我们在同样进行1+(b-a)次操作的情况下,可以得到数列:bb。
这可以说明,最终的数列最优的情况是所有位置的数均相同的。
所以我们从1-n枚举这个最优位置的数,就可以计算出:从1到这个数要经过几次操作,和这个数要复制几次。
根据基本不等式可以得知我们操作数是在sqrt(n)附近,所以真实复杂度为O(T*sqrt(n))。
#include <bits/stdc++.h>
#define int long long
using namespace std;

int T;
int n,ans;
signed main(){
	scanf("%lld",&T);
	while (T--)
	{ 
		ans=2e9;
		scanf("%lld",&n);
		for (register int i=1; i<=n; ++i)
		{
			if (i-1>=ans) break;
			ans=min(ans,(i-1)+(n-1)/i);
		}
		printf("%lld\n",ans);
	}
return 0;	
}
D. Non-zero Segments
从右往左考虑,若在[1,i]区间内,出现了字段和为0的情况,那么肯定是在i-1与i之间分割一次(即加一个超级大数或超级小数)。因为这样分割,之前的数,对后面的影响最小,只有a[i]会对后面产生影响。
那么对于字段和为0的判断,我们可以用map来存储某个数值是否出现过。
注意初始值,map[0]=1。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,l,r,mid,ans,sum;
int a[N];
map<int,int>mp;

signed main(){
	scanf("%lld",&n);
	for (register int i=1; i<=n; ++i) scanf("%lld",&a[i]);

	mp[0]=1;
	int now=0;
	for (register int i=1; i<=n; ++i)
	{
		if (mp[now+a[i]])
		{
			sum++;
			mp.clear();
			mp[0]=1;
			mp[a[i]]=1;	
			now=a[i];
		}
		else mp[now+a[i]]=1,now+=a[i];
	}
	printf("%lld\n",sum);
return 0;	
}
E. Rock, Paper, Scissors
赢得最多的情况很容易计算,那么赢得最少的情况是什么呢?肯定不是:总和减去对方赢得最多的情况。
我们需要对方去尽量抵消Alice的出拳数量,无论是对方赢还是平,均是符合要求的。
设六个数为a[1],a[2],a[3],b[1],b[2],b[3]。
那么b[1]可以抵消a[1],a[2];b[2]可以抵消a[2],a[3];b[3]可以抵消a[3],a[1]。
所以我们枚举抵消操作的顺序,对ans不断取min即可。
#include <bits/stdc++.h>
using namespace std;
int n,ans,tot,anss;
int a[10],b[10],d[10],aa[10],bb[10];
bool vis[10];
struct node{int b,a;}c[10];

void dfs(int x)
{
	int sum=0;
	memcpy(aa,a,sizeof(aa)); memcpy(bb,b,sizeof(bb));
	for (register int i=1; i<=tot; ++i) 
	{
		int minn=min(bb[c[d[i]].b],aa[c[d[i]].a]);
		bb[c[d[i]].b]-=minn; aa[c[d[i]].a]-=minn;
		sum+=minn;
	}
	ans=min(ans,n-sum);
	if (x==7)
	{
		return;	
	}
	for (register int i=1; i<=6; ++i)
	if (!vis[i])
	{
		tot++;
		d[tot]=i;
		vis[i]=true;
		dfs(x+1);
		tot--;
		vis[i]=false;
	}
	dfs(x+1);
}	

int main(){
	scanf("%d",&n);
	for (register int i=1; i<=3; ++i) scanf("%d",&a[i]);
	for (register int i=1; i<=3; ++i) scanf("%d",&b[i]);
	
	anss=min(a[1],b[2])+min(a[2],b[3])+min(a[3],b[1]);
	
	c[1]=(node){1,1};
	c[2]=(node){1,2};
	c[3]=(node){2,2};
	c[4]=(node){2,3};
	c[5]=(node){3,3};
	c[6]=(node){3,1};
	
	ans=n;
	dfs(1);
	
	printf("%d %d\n",ans,anss); 
return 0;	
}
F. Number of Subsequences
枚举每一个’?‘和’b’,然后根据前缀和可以得到:[1,i-1]的’a’,’?‘和[i+1,n]的’c’,’?'个数。
当我们取i位置作为b时,[1,i-1]可以选’a’也可以选’?’;[i+1,n]可以选’c’也可以选’?’,所以共有四种情况。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,MOD=1e9+7;
int n,ans;
int sum[N][5];
char str[N];

inline int query(int l,int r,int id)
{
	if (l>r) return 0;
	return sum[r][id]-sum[l-1][id];
}
inline int pow(int a,int nn)
{
	if (nn<0) return 0ll;
	int res=1ll;
	while (nn)
	{
		if (nn&1ll) res=res*a%MOD;
		a=a*a%MOD;
		nn>>=1ll;
	}
	return res;
}

signed main(){
	scanf("%lld",&n);
	scanf("%s",str+1);
	for (register int i=1; i<=n; ++i)
	{
		for (register int j=1; j<=4; ++j) sum[i][j]=sum[i-1][j];
		if (str[i]=='?') sum[i][4]++;
		else sum[i][str[i]-'a'+1]++;
	}
	for (register int i=1; i<=n; ++i)
	if (str[i]=='b' || str[i]=='?')
	{
		int a=query(1,i-1,4),b=query(i+1,n,4);
		ans=(ans+query(1,i-1,4)*query(i+1,n,4)%MOD*pow(3ll,a+b-2)%MOD)%MOD;//a用'?'  c用'?'
		ans=(ans+query(1,i-1,4)*query(i+1,n,3)%MOD*pow(3ll,a+b-1)%MOD)%MOD;//a用'?'  c用'c' 
		ans=(ans+query(1,i-1,1)*query(i+1,n,4)%MOD*pow(3ll,a+b-1)%MOD)%MOD;//a用'a'  c用'?'
		ans=(ans+query(1,i-1,1)*query(i+1,n,3)%MOD*pow(3ll,a+b)%MOD)%MOD;//a用'a'  c用'c' 
	}
	printf("%lld\n",ans);	
return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值