Codeforces Round #479 (Div. 3)

本文解析了五道ACM竞赛题目,包括简单的签到题、排序优化、拓扑排序、图论中的完美回路识别及最长上升子序列的求解。通过实际代码展示了多种算法的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A,B送分签到。
C的话暴力搞法直接排序,然后看看第k个数跟第k+1个数是不是一样就好了,但是一定要特判k=0||k=n的情况,wa了两发非常zz。当然想跑得更快可以二分搞搞。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int num[200005],n,k;
int check(int x)
{
    int cnt=0;
    for(int i=1;i<=n;i++)
        if(num[i]<=x)
            cnt++;
    return cnt;
}
int main()
{
    int k,i,j;
    cin>>n>>k;
    for(i=1;i<=n;i++)scanf("%d",&num[i]);
    int left=1,right=1e9,mid;
    while(left<=right){
        mid=(left+right)>>1;
        if((j=check(mid))>k){
            right=mid-1;
        }
        else if(j==k){
            cout<<mid<<endl;return 0;
        }
        else left=mid+1;
    }
    cout<<-1<<endl;

    return 0;
}

D.
注意到这样一个事实:序列从左往右3这个因子的数量是不断变少的,2这个因子是不断变多的,所以是不可逆的变换,不会成环。那么总共100个数,其实可以直接拓扑排序搞一波。更巧妙的思路则是可以根据这个特点直接进行排序:首先按照数字中3的因数个数从大到小排序,因数个数相同时则按照2的个数从小到大排序即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
int main()
{
    vector<int>G[105];int indegree[105]={0};
    int n,i,j,k;
    cin>>n;
    ll num[105];
    for(i=1;i<=n;i++)scanf("%lld",&num[i]);
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++){
        if(i==j)continue;
        if(num[j]==num[i]*2||(num[i]%3==0&&num[j]==num[i]/3)){//一定要判断能否整除3!!
            G[i].push_back(j);indegree[j]++;
        }
    }
    queue<int>que;
    for(i=1;i<=n;i++)if(indegree[i]==0)que.push(i);
    int cnt=0;
    while(!que.empty()){
        i=que.front();que.pop();
            cout << num[i] << ' ';
            for (j = 0; j < G[i].size(); j++) {
                k = G[i][j];
                indegree[k]--;
                if(!indegree[k])que.push(k);
            }

    }

    return 0;
}
#include<bits/stdc++.h>
using namespace std;
#define LL long long
struct node{
    LL a,b;
}A[110];
int cmp(node m,node n){
    if(m.b==n.b)return m.a<n.a;
    return m.b>n.b;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        cin>>A[i].a;
        LL k=A[i].a;
        while(k%3==0&&k){
            A[i].b++;
            k/=3;
        }
    }
    sort(A+1,A+1+n,cmp);
    for(int i=1;i<=n;i++)cout<<A[i].a<<" ";
}

E.
重点是注意题目描述,题目要求的是类似于一种完美的回路,没有非回路部分并且回路里面没有再回路,在这种情况下,一个点如果是回路中的一部分,当且仅当它恰好有两条边。那么我们全部扫过去dfs一遍即可。

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int>G[200005];
bool vis[200005],iscircle;
void dfs(int x)
{
    vis[x]=true;
    if(G[x].size()!=2)iscircle=false;
    for(auto a:G[x])
        if(!vis[a])
            dfs(a);
}
int main()
{
    int n,m,i,j;
    cin>>n>>m;
    for(i=1;i<=m;i++) {
        int a,b;
        scanf("%d%d",&a,&b);
        G[a].push_back(b);G[b].push_back(a);
    }
    int ans=0;
    for(i=1;i<=n;i++){
        if(!vis[i]){
            iscircle=true;
            dfs(i);
            if(iscircle)ans++;
        }
    }
    cout<<ans<<endl;

    return 0;
}

F.
用dp的思想去做吧,从前往后扫一遍,拿一个map记录以当前数为结尾的最长上升子序列长度即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
int main()
{
    map<int,int>m;//m记录的是第一个键值为结尾的最长连续上升子序列长度
    int n,i,j,k,a[200005];
    int maxn=0,maxnum;
    cin>>n;
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        j=m[a[i]]=m[a[i]-1]+1;
        if(j>maxn)maxn=j,maxnum=a[i];
    }
    cout<<maxn<<endl;
    j=maxnum-maxn+1;
    for(i=1;maxn;i++){
        if(a[i]==j){
            printf("%d%c",i,maxn==1?'\n':' ');
            maxn--;j++;
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值