1. 程式人生 > 其它 >CF#692 div2

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就完事了。