CF#692 div2

A 从后往前找连续)最长长度判断是否大于n/2即可

B 一个数字只会出现1-9,而1-9的最小公倍数为7560 所以你最多自增7560个数后必能找到符合条件的数,所以暴力模拟即可

C 因为m小于n所以必能找到符合条件的,我们想想后会发现一些规律

出现的点分为这几种情况:

1.本身就在斜对角线上,无需挪动,不管他就好

2.几个点互为环的情况例如  2,3   3,4,   4,5   5,2   这样得吧一个点换到空行去,然后....(不会讲了,反正这种情况步数是5,(环长度+1))

3.几个点为链情况  2,3  3,4  4,5  5,6   这样步数为4(链长度)(一个点也算链)

那么很明显,先连边建图,再找每条链长度,每个环大小即可

代码如下(还是建议你们想通了自己写,我的码风....一言难尽)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+107;
#define int ll
vector<int>son[N];
int hang[N];
int lie[N];
pair<int,int>a[N];
int vis[N];///标记跑过的点
void solve()
{
    int n,m;
    cin>>n>>m;
   for(int i=1;i<=n;i++) hang[i]=lie[i]=0;
    for(int i=1;i<=m;i++)
    {
        son[i].clear();
        vis[i]=0;
        cin>>a[i].first>>a[i].second;
        if(a[i].first==a[i].second) {vis[i]++;continue;}
        lie[a[i].second]=i;
        hang[a[i].first]=i;
    }
    for(int i=1;i<=n;i++)
    {
       if(hang[i]&&lie[i])
        {
            int a1=hang[i],a2=lie[i];
            son[a1].push_back(a2);
            son[a2].push_back(a1);
        }
    }
    /*for(int i=1;i<=m;i++)
    {
        cout<<i<<':';
        for(int j=0;j<son[i].size();j++) cout<<son[i][j]<<' ';cout<<endl;
    }*/
    int ans=0;
    for(int i=1;i<=m;i++)
    {
        if(vis[i]) continue;
        vis[i]++;
        if(son[i].size()==0) {ans++;continue;}///链只有一个点情况
           int d=son[i][0];
           int cnt=1;
           int last=i;
           while(d!=i)
           {
               vis[d]++;cnt++;
               if(son[d].size()==1)
                break;
               if(son[d][0]==last)
                   last=d,
                   d=son[d][1];
               else
                last=d,d=son[d][0];

           }
          if(d==i) ans+=cnt+1;///环
          else///链
          {
              if(son[i].size()==2)///当前点不为链端点
              {
                  d=son[i][1];
                  last=i;
                   while(d!=i)
                    {
               vis[d]++;cnt++;
               if(son[d].size()==1)
                break;
               if(son[d][0]==last)
                   last=d,
                   d=son[d][1];
               else
                last=d,d=son[d][0];

                    }
              }
              ans+=cnt;
          }
    }
    cout<<ans<<endl;
}
signed main()
{
    int zs;
    cin>>zs;
    while(zs--)
    solve();
}
/*
1
5 4
4 5
5 1
2 2
3 3
*/

D 看了题解,最优的结果是所有的?前部分全为0后部分全为1或全部分全为1后部分全为0,但是我不知道为什么这样就对了,前缀和维护,枚举第几个?开始,找最小ans就完事了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值