A if语句判断

如果给定的字符串是 ARC 就输出 ABC,否则输出 ARC

#include<bits/stdc++.h>
using namespace std;
string s; 
int main(){
    cin>>s;
    if(s=="ABC")puts("ARC");
    else puts("ABC");
    return 0;
}

B 数组记录+循环

遍历 $A_1,A_2\dots,A_K$ 这些序列,如果出现了数字 $i$,就用 $num$ 数组记录下来。

最后遍历一遍 $num$ 数组,输出有多少个数没出现过。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
int n,m,cnt;
int num[MAXN];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d",&cnt);
        for(int j=1;j<=cnt;j++){
            int a;
            scanf("%d",&a);
            num[a]++;
        }
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(num[i]==0)cnt++;
    }
    printf("%d",cnt);
    return 0;
}

C 简单遍历图/结构体排序

Solution 1

这道题很简单,会图论的同学可以直接建图遍历一遍即可。

#include<bits/stdc++.h>
using namespace std;
int read(){
    int s=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
    return s*f;
}
const int MAXN=1e5+5,MR=2e5+5;
struct edge{
    int from,to,nxt;//链式前向星,用nxt记录下一条边
}e[MR];
int head[MAXN],a[MAXN],cnt;
void add_edge(int u,int v){
    e[++cnt]={u,v,head[u]};//建边
    head[u]=cnt;
}
int n,m;
bool check(int x){
    for(int i=head[x];i;i=e[i].nxt){
        int v=e[i].to;//遍历图
        if(a[v]>=a[x])return false;
    }
    return true;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        add_edge(u,v);
        add_edge(v,u);
    }
    int ans=0;
    for(int i=1;i<=n;i++)ans+=check(i);
    printf("%d",ans);
    return 0;
}

Solution 2

不会图论,怎么办?

可以把所有的双向边存到结构体里面, $edge(x,y)$ 表示从 $x$ 到 $y$ 的一条边。

按照 $x$ 排序后的结构体数组可以直接判断然后解决答案。

时间复杂度 $O(m\log m)$。

#include<bits/stdc++.h>
using namespace std;
int read(){//快读,入门同学可以忽略此函数
    int s=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
    return s*f;
}
const int MR=2e5+5,MAXN=1e5+5;
int n,m,cnt,ans;
struct edge{//结构体
    int x,y;
}e[MR];
int a[MAXN],is[MAXN];
bool cmp(edge p,edge q){//结构体排序
    return p.x<q.x;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)a[i]=read(),is[i]=1;
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        e[++cnt]={u,v};//添加边
        e[++cnt]={v,u};
    }
    sort(e+1,e+cnt+1,cmp);
    int h=0,flag=1;
    for(int i=1;i<=cnt+1;i++){
        if(e[i].x!=h){//某一个元素相邻的节点都遍历完了
//          printf("%d %d\n",h,flag);
            is[h]=flag;
            flag=1;
            h=e[i].x;
        }
        if(a[e[i].y]>=a[h])flag=0;//不符要求,flag=0
    }
    for(int i=1;i<=n;i++)ans+=is[i];//统计个数
    printf("%d",ans);
    return 0;
}

D 简单for循环枚举

有些同学看了题面以后,哇! $x\le 10^{12}$,没法做了!

其实这个题目很简单,我们可以通过简单的运算得到:$^5\sqrt x \le 200$。

所以我们大胆猜想,从 $-200$ 到 $200$ 肯定有答案啊。

然后就 AC 了。

时间复杂度 $O(400^2)$。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int x;
signed main(){
    scanf("%lld",x);
    for(int i=-200;i<=200;i++){
        for(int j=-200;j<=200;j++){
            if(i*i*i*i*i-j*j*j*j*j==x){//判断条件
                printf("%lld %lld",i,j);
                return 0;
            }
        }
    }
    return 0;
}

E 式子变换

首先根据题目大意,可以列出下面的式子:

$a_i-a_j=j-i$

变换一下得:

$a_i-i=a_j+j$

我们可以枚举 $i$,所以 $i,a_i$ 都是已知的。

此时我们可以用一个 map 在循环过程中把 $a_i-i$ 记录下来,找到与它相等的 $a_i+i$,把它们的数量记录下来。

注意注意!!!必须开 long long!!!

时间复杂度 $O(n\log a_i)$。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=2e5+5;
int n,ans,a[MAXN];
map<int,int>num;
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)ans+=num[i-a[i]],num[a[i]+i]++;
    printf("%lld",ans);
    return 0;
}

F 贪心+抽屉原理

贪心的思路很好想:每一次选的两个数肯定是大的减少,小的增加。

但是如果现在减了大的,下一次操作可能不够减。

所以我们可以考虑一个时间复杂度 $O(n)$ 的离线做法。

根据抽屉原理可以知道,相邻的两次操作中,必然有一个被操作的元素相同。

在发现两次选择中数相同的时候,进行分类讨论:

若下一次操作与本次相同,就在这一次进行任意一个操作,下一次进行相反的操作,这样就使现在的状态与原来相同。

否则我们就选择与下一次重复的的那个字符这次加,保证下次可以减(即使下一次另一个不是 00 也不会出问题)。

#include<bits/stdc++.h>
using namespace std;
int q,a,b,c;
string k[100005];
char ans[100005];
int main(){
    scanf("%d%d%d%d",&q,&a,&b,&c);
    if(!a&&!b&&!c){//全部为零,直接输出NO
        puts("No");
        return 0;
    }
    for(int i=1;i<=q;i++)cin>>k[i];
    for(int i=1;i<=q;i++){
        if(k[i]=="AB"){//第一种情况,后面两种类似
            if(a>b)a--,b++,ans[i]='B';//贪心地操作
            else if(a==b&&i<q){
                if(!a){//如果全部为0就无法操作下去
                    puts("No");
                    return 0;
                }
                if(k[i+1]=="AB")ans[i]='A',ans[i+1]='B';//连续两次操作的序列相同
                else if(k[i+1]=="AC")b--,c++,ans[i]='A',ans[i+1]='C';//操作AC和AB
                else a--,c++,ans[i]='B',ans[i+1]='C';//操作BC和AB
                i++;
            }
            else b--,a++,ans[i]='A';//最后一种情况
        }
        else if(k[i]=="AC"){
            if(a>c)a--,c++,ans[i]='C';
            else if(a==c&&i<q){
                if(!a){
                    puts("No");
                    return 0;
                }
                if(k[i+1]=="AB")c--,b++,ans[i]='A',ans[i+1]='B';
                else if(k[i+1]=="AC")ans[i]='A',ans[i+1]='C';
                else a--,b++,ans[i]='C',ans[i+1]='B';
                i++;
            }
            else c--,a++,ans[i]='A';
        }
        else{
            if(b>c)b--,c++,ans[i]='C';
            else if(b==c&&i<q){
                if(!b){
                    puts("No");
                    return 0;
                }
                if(k[i+1]=="AB")c--,a++,ans[i]='B',ans[i+1]='A';
                else if(k[i+1]=="AC")b--,a++,ans[i]='C',ans[i+1]='A';
                else ans[i]='B',ans[i+1]='C';
                i++;
            }
            else c--,b++,ans[i]='B';
        }
        if(a<0||b<0||c<0){
            puts("No");
            return 0;
        }
    }
    puts("Yes");
    for(int i=1;i<=q;i++)printf("%c\n",ans[i]);
    return 0;
} 

作者 xieliren

乐观乐观再乐观

发表回复