Codeforces Round #617 (Div. 3)题解全集

很久没打cf了 被以前经常A不出题支配了 距离上次比赛 大概一个多月了 想着看看这段时间能力提升如何 只AC掉了ABCD
A题 给你一个数组 可以实现ai 和aj 把aj值赋给ai 问你能不能使得该数组之和是奇数
分析:如下思考 先记录前缀和 和奇数的个数 如果前缀和是偶数并且奇数个数=n那么肯定n是偶数 既然如此ai aj不论怎么赋值 都是奇数 不影响 所以一定会被2整除 NO构造不出 另一种情况就是奇数个数为0 也不可以构造出来 其余的yes
A

//
int main()
{
    ll p=read();
    while(p--){
        ll n=read();
        ll ans=0,cnt=0;
        for(int i=0;i<n;i++){
            ll x=read();
            if(x&1) cnt++;
            ans+=x;
        }
        if(ans%2==0&&cnt==n) printf("NO\n");
        else if(cnt==0) printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

B题意 比如给你n元去买物品 花费了x元 那么会退回我们 ⌊x/10⌋ 问我们用n元买东西 最多可以买多少钱的货
题解 模拟一下即可
B题目链接

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
 using namespace std;
inline ll read(){
    char c=getchar();
    ll f=1,x=0;
    while(c<'0'||c>'9'){
        if(c=='-')
            f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^'0');
        c=getchar();
    }
    return x*f;
}
int main()
{
    ll p=read();
    while(p--){
        ll n=read();
        ll x=round(n/10);
        ll y=round((n+x)/10);
        ll ans=0;
        while(y>x){
            x=y;
            y=round((n+x)/10);
        }
printf("%lld\n",n+y);
    }
    return 0;
}

C题 题意是什么呢? 就一个机器人的行走路线告诉了我们 询问我们最小的一个区间[l,r] 这一段区间结束的时候 机器人返回了之前经过的位置 问[l,r] 无就输出-1
题解:stl 中map的运用 标记坐标和经过的次数
C链接

int main()
{
   ll p=read();
    while(p--){
ll n=read();
string s;
cin>> s;
ll d=inf;
ll x=0,y=0,l=-1,r=-1;
map<pair<ll,ll>,ll>mp;
mp[{0,0}]=0;
for(int i=0;i<n;i++){
if(s[i]=='L')
x++;
if(s[i]=='R')
x--;
if(s[i]=='U')
y++;
if(s[i]=='D')
y--;
if(mp.count({x,y})!=0){
if( (i+1-mp[{x,y}]+1) <d){
d=i+1-mp[{x,y}]+1;
l=mp[{x,y}]+1,r=i+1;
        }
    }
mp[{x,y}]=i+1;
}
if(l==-1||r==-1) printf("-1\n");
else cout<<l<<" "<<r<<endl;
    }
    return 0;
}

D 有点意思的sort题
题意 假设ysk和yyb两人合伙打怪 一人砍一刀 固定伤害hurt-ysk hurt-yyb
并且如果怪物是ysk干掉的 积分+1 如果怪物是yyb干掉的 不加积分 而且ysk拥有k次鸡会迫使本轮yyb不砍怪 自己去砍怪
问我们两人最多能获取到积分 (我瞎编的,理解下意思就OK)
分析:对于每个怪物 都有固定的位置不可改变(但是我直接对怪物初始hp sort了一下 也AC了 后来发现这个顺序其实并不影响) 还有hp 当然我们不可能真就一刀一刀去模拟,对怪物血量模拟下最终状态 hp=hp%(hurt-ysk + hurt-yyb) 就可以知道最后一刀的归属是谁的(不使用k的鸡会) hp的预处理涉及到分类讨论 hp<=a 那么我们直接总积分++ 如果hp预处理后是0 说明此怪物必当被yyb干掉了 那么直接处理hp=(hurt-ysk + hurt-yyb)(没使用k)那么为了获得到此怪的积分 ysk必须使用一次k 给另外一个数组 存储需要使用迫使操作的次数 全部怪物预处理完了后 对使用迫使鸡会的数组sort一下 从小往大取 直到>=k 此法最贪

//
#include<bits/stdc++.h>
#include<cmath>
#include<string.h>
#include<streambuf>
#include<algorithm>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
using namespace std;
inline const int read()
{
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); }
    return x * f;
}//快读
int num[200009],e=0,add2=0,y=0;
const int manx=1e5+5;
int main()
{int sum[200009],n,i,a,b,k,add=0,r,change=0;
cin>>n>>a>>b>>k;
for(i=0;i<n;i++){
    cin>>sum[i];
}
sort(sum,sum+n);
for(i=0;i<n;i++){
r=sum[i]%(a+b);//砍
if(r==0){r=a+b;}
if(r<=a){add++;continue;}
if(r-a>0){
//一刀砍不死 a砍不死 b一定坎德斯
r=r-a;
if(r%a==0){
num[e]=r/a;}
else{
 num[e]=r/a+1;
}
  e++;
}
}
sort(num,num+e);
for(i=0;i<e;i++){
   add2=add2+num[i];
    if(add2<=k){y++;}
    else{break;}
}
printf("%d",add+y);
return 0;
}

E1 E2 其实都要我们找非降序的子序列 只是数据不一样
模拟一下即可

E2 
 ll a[30];
int main()
{ 
    ll n=read();
    string s;
    cin>>s;
    vector<ll>ans;
  
   
    ll res=1;
    for(int i=0;i<n;i++){
        ll  d=1;
        for(int j=s[i]-'a'+1;j<26;j++)
            d=max(d,a[j]+1);
        a[s[i]-'a']=d;
        ans.push_back(d);
        res=max(res,d);
    }
    cout<<res<<endl;
    for(int i=0;i<ans.size();i++)
        cout<<ans[i]<<" ";
    cout<<endl;
    return 0;
}


E1
int main()
{
    ll n=read();
    string s;
    cin>>s;
    char c1='a',c2='a';
    string ans="";
    for(int i=0;i<n;i++){
        if(c1<=s[i]){
            c1=max(c1,s[i]);
            ans+="0";
        }
        else if(c2<=s[i]){
            c2=max(c2,s[i]);
            ans+="1";
        }
        else{
           printf("NO\n");
            return  0;
        }
    }
    printf("YES\n");
    cout<<ans<<endl;
    return 0;
}

F LCA
给定一棵n个点的树以及n-1条边,现在给出m组ui,vi,wi,表示ui到vi这条最短路径上的最小边权是wi,要你构造出树的边权。
树上两点的最小边权可以通过lca的方法来遍历求出,关键是怎么构造边权?其实可以把给出的m组条件按从大到小排序,只要保证i点和j点的路径上是权值最大的边先赋值就行。

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e3+1;
const int INF=1e6;
int n,m,num[maxn],size[maxn],ans[maxn],father[maxn],deep[maxn];
struct cxk{
	int v,id;
};
struct node{
	int u,v,w;
}s[maxn];
vector<cxk>g[maxn];
bool cmp(const node &a,const node &b)
{
	return a.w>b.w;
}
void dfs(int u,int fa)
{
	father[u]=fa;
	deep[u]=deep[fa]+1;
	for(auto to:g[u])
	{
		if(to.v==fa) continue;
		dfs(to.v,u);
		size[to.v]=to.id;
	}
	num[u]=INF;
}
bool check(int x,int y,int k)
{
	int minn=INF;
	if(deep[x]<deep[y]) swap(x,y);
	while(deep[x]!=deep[y])
	{
		if(num[x]==INF) num[x]=k;
		minn=min(minn,num[x]);
		x=father[x];
	}
	while(x!=y)
	{
		if(num[x]==INF) num[x]=k;
		minn=min(minn,num[x]);
		x=father[x];
		if(num[y]==INF) num[y]=k;
		minn=min(minn,num[y]);
		y=father[y];
	}
	return minn==k;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		g[u].push_back({v,i});
		g[v].push_back({u,i});
	}
	dfs(1,0);
	scanf("%d",&m);
	for(int i=1;i<=m;++i){
		int u,v,w;
		scanf("%d %d %d",&s[i].u,&s[i].v,&s[i].w);
	}
	sort(s+1,s+1+m,cmp);
	for(int i=1;i<=m;++i){
		if(!check(s[i].u,s[i].v,s[i].w)) {
			puts("-1");return 0;}
	}
	for(int i=2;i<=n;++i) ans[size[i]]=num[i];
	for(int i=1;i<n;++i) printf("%d ",ans[i]);
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值