Codeforces Round #580 (Div. 2)

A题---水题:

int a[105],b[105];
int main()
{
    int n1,n2;
    cin>>n1;
    for(int i=0;i<n1;i++)
    cin>>a[i];
    sort(a,a+n1);
    cin>>n2;
    for(int i=0;i<n2;i++)
    cin>>b[i];
        sort(b,b+n2);
    
    cout<<a[n1-1]<<" "<<b[n2-1]<<endl;
 } 

 

B题---模拟题

题意:给定n个数字(数字范围为10^9ai10^9),每个数字可以进行原基础上的加一或减一操作,问多少次操作之后这些数字的乘积为1?

思路:

要数字乘积为1   那么这些数字必须为-1与1

所以我们需要做的是让这些数字都靠近1与-1,另外处理数字0---使他看情况变为1或-1

-3 -5 -5  -1 0 0 0 1 2 

注明:这里需要处理一些细节

int main()
{
    int n,t;
    cin>>n;
    int a=0,b=0,c=0;
    long long ans=0;
    for(int i=0;i<n;i++)
    {
        cin>>t;
        if(t==0)
        c++;
        else if(t>0)
        {
            a++;
            ans+=(t-1);
        }
        else
        {
            b++;
            ans+=(-1-t);
        }
     }
        if(c==0)
        {
            if(a==0&&b)
            {
                if(b%2==1)
                ans+=2;
            }
            if(a&&b)
            {
                if(b%2==1)
                ans+=2;
            }
        }
        else
        {
            ans+=c;
        }
        cout<<ans<<endl;
 } 

 

C题:规律模拟题

题意:给定数字n,让你求一个环,环上有2n个数字(1,2...2n),环上形成连续的n个数字其和与其他的环上形成连续的n个数字的和相差不大于1,问是否存在这样的环,存在输出该环

思路:我们可以得出a[i]-a[i+n]=1(或者-1)   即a[i]与a[i+n]相差1

我们只需求出n对这样的数    每对数两数之间相差1    其实就是1,2 ;3,4;5,6;然后我们注意到每次都是先相差正1,然后下一组相差负1

int a[200005];
int main()
{
    int n;
    cin>>n;
    n=2*n; 
    int sum=n*(n+1)/2;
    int x=(sum+1)/2;
    a[1]=1,a[n]=n;
    if((n/2)%2==0)
    cout<<"NO"<<endl;
    else{
    int t=1;
    for(int i=1;i<=n/2;i++)
    {
        t=2*i;
        if(i%2)
        {
            a[i]=t-1,a[n/2+i]=t;
        }
        else
        {
            a[i]=t,a[n/2+i]=t-1;
        }        
    }
    cout<<"YES"<<endl;
    for(int i=1;i<=n;i++)
    {
        if(i!=n)
        cout<<a[i]<<" ";
        else
        cout<<a[i]<<endl;
    }
    }
 } 

 

 d题

思路:题目可以转化为求图中的最小环,从一个点去找路径,然后结束条件就是路径点又回到了起点,这就是环。然后记录最小的环的边数目。

枚举每个点的最小环

给你n个点,每个点都有权值,两个点当且仅当(ai&aj)!=0时才会有边.
让你求最小的循环长度 (循环中的点要大于等于3)


点的权值的上限是1e18,比2^60小.
易得结论:n>120时必定存在一个循环长度为3的环
假设前60个点每个点都不会与其他点连边,这是最坏的情况,也就是每个点都是2的k次方这样子
那么后面不论加什么点都会与前面60个点的其中至少一个点连有边,再考虑最坏的情况,加入120
个点后恰好每两个点有边,此时再加入任意一个点,即存在一个环.
注意点的权值可以为0,把权值为0的点剔除就好.
对于n<=120 跑个floyd最小环

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define maxn 100010
 5 const int inf = 0x3f3f3f3f; 
 6 ll a[maxn];
 7 int path[500][500];
 8 ll cost;
 9 int vis[500],m;
10 
11 void dfs(int u,int cnt,int x)//当前点  边数   遍历点的起点 
12 {
13     vis[u]=1;
14     if(cnt>cost) //剪枝 
15     return;
16     if(cnt>=3&&path[u][x])
17     {
18         cost=cnt;
19         return;
20      } 
21     
22     for(int v=1;v<=m;v++)
23     {
24         if(vis[v]==0&&path[u][v]&&v!=x)
25         {
26         //    vis[i]=1;
27             dfs(v,cnt+1,x);
28             vis[v]=0;
29         }
30     }
31     
32 }
33 
34 int main()
35 {
36     int n;
37     scanf("%d",&n);
38     ll a[maxn],kk;
39     m=0;
40     for(int i=1;i<=n;i++)
41     {
42         scanf("%lld",&kk);
43         if(kk!=0)
44         {
45             m++;
46             a[m]=kk;
47         }
48         
49     }
50     
51     if(n>=200)
52     printf("3\n");
53     else
54     {
55     //    memset(path,-1,memset(path));
56         for(int i=1;i<=m;i++)
57         for(int j=1;j<=m;j++)
58         {
59             if(a[i]&a[j])
60             path[i][j]=1;
61         }
62         ll ans=1ll*inf; 
63         for(int i=1;i<=m;i++)//遍历每个点的最小环的长度 
64         {
65             memset(vis,0,sizeof(vis));
66             cost=1ll*inf;
67             dfs(i,1,i);
68             ans=min(ans,cost);
69         }
70         
71         cout << (ans == inf ? -1 : ans) << endl;
72     }
73  } 
View Code

 


借鉴的原文链接:https://blog.csdn.net/qq_41608020/article/details/99716916

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f;
 
int n, m, mp[500][500];
LL a[N], b[N], ans = 1LL * inf, now;//1LL 是为了在计算时,把int类型的变量转化为long long,然后再赋值给long long类型的变量。 
bool vis[500];
 
void dfs(int u, int w, int rt) { //w表示该路径的边的数目  u表示路径现在走到的点   rt表示枚举的这个环的起点也即终点 
    vis[u] = 1;
    if(w > now) return;   //所走的步数大于之前存的最短路径 
    if(w >= 3 && mp[u][rt]) {  //说明走的路径形成环
        now = w;
        return;
    }
    
    for(int v = 1; v <= m; v++) {  //可走的路径 
        if(mp[u][v] && vis[v] == 0 && v != rt){
            dfs(v, w + 1, rt);
            vis[v] = 0;
        }
    }
}
 
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        if(a[i]) b[++m] = a[i];//b数组存非0的所以数字 
    }
    if(m >= 200) puts("3");  //这个是大佬们发现的规律吧   
    else {
        for(int i = 1; i <= m; i++) 
        for(int j = 1; j <= m; j++) 
        if(b[i] & b[j]) mp[i][j] = 1; //说明节点i,j被连接 
        
        for(int i = 1; i <= m; i++) { //枚举环的起点 
            memset(vis, 0, sizeof vis);
            now = inf;
            dfs(i, 1, i); //路径当前所走到的点     路径点的个数    路径起点 
            ans = min(ans, now);//获得最短的周期 
        }
        cout << (ans == inf ? -1 : ans) << endl;
    }
}

 

     

 

posted @ 2019-08-19 13:13  saaas  阅读(180)  评论(0)    收藏  举报