Codeforces Round #582 (Div. 3)

A:先免费跳2,最终情况是都跳在x和x+1的位置。奇偶取min即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n;
  	cin>>n;
  	int x,j=0,o=0;
  	for(int i=1;i<=n;i++)
	{
		cin>>x;
		if(x&1)j++;
		else o++;
	}
	cout<<min(j,o)<<endl;
	return 0;
}

B:逆序,判断是否小于前面最小即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 1e6+7;
int a[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
	int t,n;
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)cin>>a[i];
		int mi=1e9,ans=0;
		for(int i=n;i>=1;i--)
		{
			if(a[i]>mi)ans++;
			mi=min(a[i],mi);
		}
		cout<<ans<<endl;
	}
	return 0;
}

C:

方法一:

只跟末尾有关,循环节最长为10

我直接找循环节,搞搞就行

方法二:

最终的数是:m,2*m,3*m ……11*m,12*m……n/m *m

我们统计下[1,n/m]中末尾1-9出现的次数,

一个末尾i的数的贡献是:(i*m)%10;

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int xh[20];
int vs[20];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int t;
  	cin>>t;
  	while(t--)
  	{
  		memset(vs,0,sizeof(vs));
  		memset(xh,0,sizeof(xh));
  		ll n,m;
		cin>>n>>m;
  		ll nm=n/m;//写几次
		ll tp=m%10;//末尾为tp 
  		int sz=0;
  		ll w=0;
  		ll now=tp;
  		while(1)
		{
			if(vs[tp])break;
			vs[tp]=1;
			xh[++sz]=tp;w+=tp;
			tp=(tp+now)%10;
		}
		ll xhnm=nm/sz;
		ll ans=xhnm*w;
		for(int i=1;i<=nm%sz;i++)
		ans+=xh[i%sz];
		cout<<ans<<endl;
	}
	return 0;
}

D:记录每个数出现的最大次数,和到达这个数用的次数集合。

取次数最小的k次即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 2e5+7;

int a[M];
int ct[M];
multiset<int>s[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	sort(a+1,a+1+n);
	for(int i=1;i<=n;i++)
	{
		int tp=a[i],nt=0;
		while(tp)
		{
			ct[tp]++;
			s[tp].insert(nt);
			nt++;
			tp/=2;
		}
	}
	ll mi=1e18;
	for(int i=1;i<=200000;i++)
	{
		if(ct[i]>=k)
		{
		//	cout<<i<<" "<<ct[i]<<endl;
			ll ans=0,tp=0;
			for(auto x:s[i])
			{
			//	cout<<x<<" ";
				ans+=x;
				tp++;
				if(tp==k)break;
			}
		//	cout<<"  --"<<endl;
			mi=min(ans,mi);
		}
	}
	cout<<mi<<endl;
	return 0;
}

E:

如果s,t  都不是两个字符相同的情况,  我们枚举"abc"的全排列,得到满足条件的串xyz.最后输出  xxxyyyzzz的形式即可,这样出现的子串为:xy,yz,判断下s、t都不为xy,yz就说明这个全排列可行。

如果s,t出现重复字符  例如:s:“aa”,假设找到可以的串,xyz,最后输出xyzxyzxyz的形式。

这种情况子串为:xy,yz,zx   要同时满足s、t都不等于这三个子串 才说明这个全排列可行

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 1e5+7;
char s1[4],s2[4];
char s[3]={'a','b','c'};
void gao1()
{
	do
	{
		bool f=false;
		for(int i=0;i<=1;i++)
		{
			if(s[i]==s1[0]&&s[i+1]==s1[1])f=true;
			if(s[i]==s2[0]&&s[i+1]==s2[1])f=true;
		}
		if(!f)break;//s1,s2都不是S的子串 
	}while(next_permutation(s,s+3));
}
void gao2()
{
	do
	{
		bool f=false;
		for(int i=0;i<=1;i++)
		{
			if(s[i]==s1[0]&&s[i+1]==s1[1])f=true;
			if(s[i]==s2[0]&&s[i+1]==s2[1])f=true;
		}
		if(s[2]==s1[0]&&s[0]==s1[1])f=true;
		if(s[2]==s2[0]&&s[0]==s2[1])f=true;
		if(!f)break;//s1,s2都不是S的子串 
	}while(next_permutation(s,s+3));
}
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	int n;
  	cin>>n;
  	cin>>s1>>s2;
  	cout<<"YES"<<endl;
  	if(s1[0]==s1[1]||s2[0]==s2[1])
  	{
  		gao2();
  		for(int i=1;i<=n;i++)cout<<s;
	}
  	else
  	{
  		gao1();
  	//	cout<<s<<endl;
  		for(int j=0;j<=2;j++)
  		for(int i=1;i<=n;i++)cout<<s[j];
	}
	return 0;
}

G:

如果是单次询问的话非常简单:

删去边权>=q的边,然后得到一颗颗子树,对每颗子树求任意满足u<v 点对u,v的个数 (其实就是联通块大小sz,sz*(sz-1)/2)

但这题是多次。

由于是问路径上最大值,我们不妨从边权最小的开始加入,

假设加入到边权为wi的边,此时qi<w的所有情况都已经确定,因为其他边都是大于等于w的。

对于这条边,会给所有qi>=w 的情况 带来  siz[gu]*sz[gv]个点对的贡献。

上述操作用差分处理下即可。

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 2e5+7;
struct node{
	int u,v,w;
}ee[M];
bool cmp(node a,node b)
{
	return a.w<b.w;
}
int fa[M];
ll siz[M];
int get(int x)
{
	if(fa[x]==x)return fa[x];
	return fa[x]=get(fa[x]);
}
ll ans[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
	int n,q,u,v,w;
	cin>>n>>q;
	for(int i=1;i<=n-1;i++)
		cin>>ee[i].u>>ee[i].v>>ee[i].w,fa[i]=i,siz[i]=1;
	fa[n]=n,siz[n]=1;
	sort(ee+1,ee+n,cmp);//按边权从大到小 
	for(int i=1;i<n;i++)
	{
		u=ee[i].u,v=ee[i].v,w=ee[i].w;
		int gu=get(u),gv=get(v);
	//	cout<<u<<"  "<<v<<" "<<w<<" ="<<siz[gu]<<" "<<siz[gv]<<endl;
		ans[w]+=siz[gu]*siz[gv];
		fa[gu]=gv;
		siz[gv]+=siz[gu];
	}
	for(int i=1;i<=200000;i++)ans[i]+=ans[i-1];
	while(q--)
	{
		int x;
		cin>>x;
		cout<<ans[x]<<" ";
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值