Codeforces Round 923 (Div. 3) def

d.Find the Different Ones!

#include<iostream>
#include<cstring>
using namespace std;
//这个题的关键就是要想到 如果这个区间里有不同的数 那么一定会有与a[l]不同的数 
//直接看a[l]的最近的不同的数有没有出现在区间中即可
int t;
int a[1000009];
int d[1000009];
int main()
{
    cin>>t;
    while(t--)
    {
        memset(a,0,sizeof(a));
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        cin>>a[i];
        for(int i=n;i>1;i--)
        {
            if(a[i]!=a[i-1])
            d[i-1] = i;
            else d[i-1] = d[i];
        }
        int q;
        cin>>q;
        while(q--)
        {
            int l,r;
            cin>>l>>r;   
            if(r>=d[l]&&d[l]) 
            cout<<l<<" "<<d[l]<<endl;
            else cout<<-1<<" "<<-1<<endl;
        }
    }

    return 0;
}

e.Klever Permutation

#include<iostream>
#include<cstring>
using namespace std;
//这个题最关键的是要想到怎样可以使k连续的数的和之间的差不超过1
//实现这个的直接方法就是让第i个数比第i-k个数大1或小1
//并且保证是对于前一个数是大1 对于后一个数就要是小1 不然前后的和之间的差就会超过1
//我的想法就是奇数位从小到大递增 偶数位从大到小递减
int t;
int a[200009];
int main()
{
    cin>>t;
    while(t--)
    {
        memset(a,0,sizeof(a));
        int n,k;
        cin>>n>>k;
        int s=1,b=n;  //排数列的数 s是从小到大的奇数位 b是从大到小的偶数位
        int cent = 0;
        int i=1;      //有点类似于把n分成k个区间 每次填每个区间里的一个数 i就是这个数在区间中的位数
        while(cent<n)
        {
            if(i%2==1)   //如果是奇数位
            {
                for(int j=i;j<=n;j+=k)  //每隔k位填一次 每次加1
                {
                    a[j] = s;
                    s ++;
                    cent ++;
                }
            }else  //如果是偶数位
            {
                for(int j=i;j<=n;j+=k)  //每隔k位填一次 每次减1
                {
                    a[j] = b;
                    b --;
                    cent ++;
                }
            }
            i ++;   //下一个区间位置
        }
        for(int i=1;i<=n;i++)
        {
            cout<<a[i]<<" ";
        }
    }

    return 0;
}

f.Microcycle

这个题比较难,用到的知识点比较多
暴力的做法肯定就是从最小边开始一个一个的试能不能成环
时间复杂度大概是o(n^2)
关键就在于怎么准确的找到这个最小边 只进行一次dfs找环
用到的就是kruskal算法 利用并查集 找到非树边中的最小边
这里需要将边从大到小排序 将所有树边排除 找到最后一个非树边 就是成环中的最小边
这里不是从小到大排序,如果是从小到大,形成的环不一定包括前面的最小边,而从大到小,则保证了最后的最小非树边,一定包括在环中。
将这个最小边的两端 作为起点和终点,进行dfs,查找路径

#include<iostream>
#include<algorithm>
using namespace std;
int t,n,m;
struct edge
{
    int u,v,w;
} e[200009];
bool cmp(struct edge e1,struct edge e2)
{
    return e1.w>e2.w;
}
int fa[200009];
int find(int x)
{
    if(x==fa[x]) return x;
    return fa[x] = find(fa[x]);
}
//利用kruskal从大到小 建立最小生成树 最后一个不符合条件的非树边 就是最小边
//从小到大的话 可能形成的环并不包括最小边
int find_min()
{
    int num;
    for(int i=1;i<=n;i++) fa[i] = i;
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        int x = find(e[i].u);
        int y = find(e[i].v);
        if(x==y)
        num = i;   //非树边中的最小边   
        else fa[x] = y;
    }
    return num;
}
int beg,last,cent;
int ans[200005];
int first[200005],vis[200009];
struct node
{
    int to,next;
}e2[200009*2];
void add(int u,int v)
{
    cent ++;
    e2[cent].to = v;
    e2[cent].next = first[u];
    first[u] = cent;
}
int sum ;
int flag = 0;
//以找到的最小边的两端 进行dfs 找到路径
void dfs(int a,int num)
{
    if(flag) return;
    ans[num] = a;
    //cout<<ans[num]<<"   "<<num<<endl;
    if(a==last) 
    {
        flag = 1;
        sum = num;
        return;
    }
    for(int i=first[a];i;i=e2[i].next)
    {
        int to = e2[i].to;
        if(num==1&&to==last||vis[to]==1) continue;
        vis[to] = 1;       //不能溯洄 如果溯洄会超时相当于遍历了整个图 肯定不用走之前走过的路 如果需要的话第一走就可以
        dfs(to,num+1);     //第一次走发现到不了 之后也不需要经过这个点
    }
}
int main()
{
    cin>>t;
    while(t--)
    {
        for(int i=1;i<=n;i++)
        {
            ans[i] = 0;
            vis[i] = 0;
            first[i] = 0;
        }
        beg=0,last=0,cent=0;
        sum = 0,flag = 0;
        scanf("%d%d",&n,&m);
        //cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
            //cin>>e[i].u>>e[i].v>>e[i].w;
        }
        int minnum = find_min();
        beg = e[minnum].u;
        last = e[minnum].v;
        //cout<<last<<"   last"<<endl;
        for(int i=1;i<=m;i++)
        {
            add(e[i].u,e[i].v);
            add(e[i].v,e[i].u);
        }
        vis[beg] = 1;
        dfs(beg,1);
        printf("%d %d\n",e[minnum].w,sum);
        //cout<<e[minnum].w<<" "<<sum<<endl;
        for(int i=1;i<=sum;i++)
        printf("%d ",ans[i]);
        //cout<<ans[i]<<" ";
    }

    return 0;
}

g题太难了,本菜鸟还还看不懂……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值