Gym - 102348(待补)

A Yellow Cards(贪心)

题意:裁判有n张卡,a队的每个人需要k1张卡才能罚下场,b队需要k2张卡才能罚下场。求罚下场的最少和最多的人数。

题记:简单贪心,要罚下场的人最多就从k小的那支队伍开始,最少情况的话判断一下能不能至少给每个人留一张牌,能则为0,不能则算出罚下场的人数。

#include<iostream>
#include<algorithm>
using namespace std;

int main(){
    int a1,a2,k1,k2,n;
    cin>>a1>>a2>>k1>>k2>>n;
    int sum=a1*k1+a2*k2;
    int a=a1+a2;
    int ans1,ans2;
    if(n<=sum-a) ans1=0;
    else{
        ans1=n-(sum-a);
        if(ans1>a) ans1=a;
    }
    if(n>=sum) ans2=a;
    else if(k1<k2){
        if(n<a1*k1) ans2=n/k1;
        else ans2=a1+(n-a1*k1)/k2;
    }
    else{
        if(n<a2*k2) ans2=n/k2;
        else ans2=a2+(n-a2*k2)/k1;
    }
    cout<<ans1<<' '<<ans2<<endl;
    return 0;
}

B Interesting Vertices(DFS)

题意:给出一颗树,有n个点个n-1条边,其中有k个点是染了色的,求以每个点为根节点的所有子树都有染色的点的个数。

题记:首先用邻接表把图先存下来,从1这个节点开始DFS。

首先我们是利用DFS的回溯来判断这个点的所有子树是否有染色。用一个st数组来存当前子树的染色个数。由于st数组不包括父节点的染色数量,所以要判断一下k-st[u]是否大于0(即父节点有没有被染色),1除外(因为我们是从1开始遍历的,1没有父节点)。

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
int color[N];
int vis[N];
int st[N];
int n,k;
struct Edge{
    int to,next;
}edge[N*2];
int head[N],cnt;
vector<int>ans;
void addedge(int u,int v){
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}

void dfs(int u){
    //out<<u<<endl;
    vis[u]=1;
    int flag=1;
    st[u]=color[u];
    for(int i=head[u];i!=-1;i=edge[i].next){
        int j=edge[i].to;
        if(vis[j]) continue;
        dfs(j);
        if(!st[j])flag=0;
        st[u]+=st[j];
    }
    if(!color[u]&&flag&&(k-st[u]>0||u==1))ans.push_back(u);
}

int main(){
    cin>>n>>k;
    int x;
    for(int i=0;i<k;i++){
        cin>>x;
        color[x]=1;
    }
    cnt=0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        addedge(u,v);
        addedge(v,u);
    }
    dfs(1);
    //for(int i=1;i<=n;i++) cout<<st[i]<<endl;
    sort(ans.begin(),ans.end());
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++)
        cout<<ans[i]<<' ';
    cout<<endl;
    return 0;
}

C

D Ticket Game(博弈)

题意:给出一个数组,M和B可以把数组中的问号变成0-9任意一个数,只要前n/2个数的和等于后n/2个数,那么就B赢,否则M赢。

题记:可以把题目分为三种情况。

1、没有问号,那么直接判断左右两边的和是否相等即可。

2、只有一边有问号,这样需要没有问号的那边的和减去有问号那边的和等于问号/2*9。这是B的必胜态,因为无论W填什么数,B都可以填上一个数使得填的这两个数加起来等于9。

3、两边都有问号,这种情况可以转换为第二种情况,就是当M在一边填上一个数时,B在另一边填上一个相同的数。

#include<iostream>
#include<cmath>
using namespace std;
const int N=2e5+10;
char s[N];
int main(){
    int n;
    cin>>n;
    int sum1=0,sum2=0;
    int hn=n/2;
    int wh1=0,wh2=0;
    for(int i=0;i<n;i++){
        cin>>s[i];
        if(i<hn){
            if(s[i]=='?') wh1++;
            else sum1+=s[i]-'0';
        }
        else{
            if(s[i]=='?') wh2++;
            else sum2+=s[i]-'0';
        }
    }
    int flag=0;
    if((wh2-wh1)/2*9==sum1-sum2)flag=1;

    if(flag) cout<<"Bicarp"<<endl;
    else cout<<"Monocarp"<<endl;
    return 0;
}

E

F The Number of Products(递推)

题意:给出n个数,求区间乘积为正数,0,负数的数量。

题记:dp1[i]表示以i为结尾的乘积为正数的个数,dp2[i]表示以i结尾的乘积为负数的个数,dp3[i]表示以i结尾乘积为0的个数。
最后结果就是dp数组的总和。
也是分为3种情况:

1、当前这个数是正数,dp1[i]=dp1[i-1]+1,dp2和dp3不变。

2、当前这个数是负数,dp1[i]=dp2[i-1],dp2[i]=dp1[i-1]+1,由于当前这个数是负数,所以乘积需要乘上一个负数,那么正数是由dp2[i-1]转换过来,负数同理。

3、当前这个数是0,由于0乘任何数都为0,所以dp3[i]=i。此时dp1和dp2都要清0。

#include<iostream>

using namespace std;
const int N=2e5+10;
typedef long long ll;
int a[N];
int dp1[N],dp2[N],dp3[N];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        if(a[i]>0){
            dp1[i]=dp1[i-1]+1;
            dp2[i]=dp2[i-1];
            dp3[i]=dp3[i-1];
        }
        else if(a[i]<0){
            dp1[i]=dp2[i-1];
            dp2[i]=dp1[i-1]+1;
            dp3[i]=dp3[i-1];
        }
        else{
            dp1[i]=0;
            dp2[i]=0;
            dp3[i]+=i;
        }
    }
    ll ans1=0,ans2=0,ans3=0;
    for(int i=1;i<=n;i++){
        //cout<<dp1[i]<<' '<<dp2[i]<<' '<<dp3[i]<<endl;
        ans1+=dp2[i];
        ans2+=dp3[i];
        ans3+=dp1[i];
    }
    cout<<ans1<<' '<<ans2<<' '<<ans3<<endl;
    return 0;
}

G Swap Letters(思维)

题意:两个只含a,b的字符串,可以让两个字符串的字母进行交换,最终使得两个字符串相等。求最小交换次数和交换的位置。

题记:交换有两种情况。
1、
a a
b b
这种情况只需要换一次,优先换这样的情况。
2、
a b
b a
这种情况需要换两次。

那么先换第一种情况,再换第二种情况即可。

#include<iostream>
#include<vector>
using namespace std;
const int N=2e5+10;
typedef pair<int,int>PII;
char s[N],t[N];
int main(){
    int n;
    cin>>n;
    cin>>s;
    vector<int>num1;
    vector<int>num2;
    for(int i=0;i<n;i++){
        cin>>t[i];
        if(s[i]!=t[i]){
            if(s[i]=='a'){
                num1.push_back(i+1);
            }
            else{
                num2.push_back(i+1);
            }
        }
    }
    int len1=num1.size(),len2=num2.size();
    int ans=0;
    if((len1+len2)%2==1){
        ans=-1;
        cout<<ans<<endl;
    }
    else{
        ans+=len1/2+len2/2;
        if(len1%2) ans+=2;
        cout<<ans<<endl;
        while(len1>1){
            len1-=2;
            int x=num1.back();
            num1.pop_back();
            int y=num1.back();
            num1.pop_back();
            cout<<x<<' '<<y<<endl;
        }
        while(len2>1){
            len2-=2;
            int x=num2.back();
            num2.pop_back();
            int y=num2.back();
            num2.pop_back();
            cout<<x<<' '<<y<<endl;
        }
        if(len1){
            int x=num1.back();
            cout<<x<<' '<<x<<endl;
            int y=num2.back();
            cout<<x<<' '<<y<<endl;
        }
    }
    return 0;
}

H

I

J

K

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值