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;
}