Codeforces Round #749 (Div.1+Div.2)A-D题解

A. Windblume Ode
题意:就是从n个数里面挑p(要求最大)个数的和为合数,输出所挑选的数的下标,顺序随便
思路:p的可能值只有n or n-1,如果所有加起来的和为合数,输出n,否则,在奇数中挑一个数减去,使得和为合数,
证明:假设偶数有a个,奇数有b个,a个偶数相加肯定为合数,
(1)如果b是偶数,则奇数可以两两配对,所以最后的和为偶数,肯定为合数
(2)如果b为奇数,那么最后的和可能为合数,可能不是,如果不是,和肯定为奇数,所以需要减去一个奇数,使得和为合数
代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        int a[200];
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            sum+=a[i];
        }
        int flag=0;
        for(int i=2;i*i<=sum;i++)
        {
            if(sum%i==0)
            {
                flag=1;
                break;
            }
        }
        if(flag)
        {
            cout<<n<<endl;
            for(int i=1;i<=n;i++)
            {
                cout<<i<<" ";
            }
            cout<<endl;
        }
        else
        {
            int k=0;
            cout<<n-1<<endl;
            for(int i=1;i<=n;i++)
            {
                if(a[i]%2&&k==0)
                {
                    int f=0;
                    for(int j=2;j*j<=sum-a[i];j++)
                    {
                        if((sum-a[i])%j==0)
                        {
                            f=1;
                            break;
                        }
                    }
                    if(f)
                    {
                        k=1;
                        continue;

                    }
                    else
                    {
                        cout<<i<<" ";
                    }
                }
                else
                {
                    cout<<i<<" ";
                }
            }
            cout<<endl;
        }
    }
}

B. Omkar and Heavenly Tree
题意:有一个n节点的图,有m个限制,输入限制a b c,代表a c中间的简单路径中不能有b节点,(n>m)构造这个图
思路:因为n>m所以肯定有一个节点没有任何限制,我们可以把它放中间,其他点围成一圈,就可以了,这样点和点之间都是这个没有任何限制的点,
代码

#include<bits/stdc++.h>
using namespace std;
int vis[100005];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            vis[b]=1;
        }
        int id=0;
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0)
            {
                id=i;
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(id==i)continue;
            cout<<id<<" "<<i<<endl;
        }
    }
}

C. Omkar and Determination
题意:有一个n×m图,有些格子被填充,有些空着,空单元格可通过,向上或向左移动走出边界,所以我们可以通过原图确定一个新图,上面标记着那些单元个可以走出边界那些不行,这个新图也可以反推出原图,如果这个新图反推出的图是唯一的,则称这个原图是可确定的,现在问你由Xn,Xn+1,··· Xn+m列组成的图是不是可确定的
思路:如果一个空单元格走不出边界,那么这个单元格对应的新图上走不出去,那么这个单元格也可以是填充的,所以这个点反推回来会有两种情况,所以我们要统计原图上空单元格走不出去的点,利用前缀和,如果q[l]=q[r]代表l+1~r间没有不符合的点,输出YES,否则输出NO,并且,如果查询范围l=r直接输出YES
代码

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<cstring>
using namespace std;
int vis[1000005];
int q[1000005];
char s[1000005];
char c[1000005];
int main()
{
    int n, m;
    cin >> n >> m;
    int cnt = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> c;
        for (int j = 0; j < m; j++)
        {
            if (i > 0 && j > 0)
            {
                if (s[j] == 'X' && c[j - 1] == 'X')
                {
                    vis[j]++;
                }
            }
        }
        strcpy(s, c);
    }
    for (int i = 1; i < m; i++)
    {
        q[i] = q[i - 1] + vis[i];
    }
    int t;
    cin >> t;
    while (t--)
    {
        int l, r;
        cin >> l >> r;
        if (l == r)cout << "YES" << endl;
        else
        {
            r--,l--;
            if (q[r] == q[l])
                cout << "YES" << endl;
            else
            {
                cout << "NO" << endl;
            }
        }
    }
}

D. Omkar and the Meaning of Life
题意:你可以查询不超过2*n次,每次查询输出a1~an,设sj=aj+pj;如果s中有重复的,会返回第一个重复值的下标,求p数组(p数组是n的一个排列,里面每个数在1到n之间,不重复)
思路:
Codeforces Round #749 (Div.1+Div.2)A-D题解
每次查询可以得到其它数与pn的差距
Codeforces Round #749 (Div.1+Div.2)A-D题解
左边得到比pn小的数的差距,右边得到比pn大的数的差距
代码

#include<bits/stdc++.h>
using namespace std;
int d[110];
int n;
int main()
{
    cin>>n;
    for(int i=2;i<=n;i++)
    {
        cout<<"? ";
        for(int j=1;j<n;j++)
        {
            cout<<i<<" ";
        }
        cout<<1<<endl;
        fflush(stdout);
        int x;
        cin>>x;
        d[x]=1-i;//与pn的差距
    }
    for(int i=2;i<=n;i++)
    {
        cout<<"? ";
        for(int j=1;j<n;j++)
        {
            cout<<1<<" ";
        }
        cout<<i<<endl;
        fflush(stdout);
        int x;
        cin>>x;
        d[x]=i-1;
    }
    int mi=1;
    for(int i=1;i<=n;i++)
    {
        if(d[mi]>d[i])
        {
            mi=i;
        }
    }
    int ans=-d[mi]+1;
    cout<<"! ";
    for(int i=1;i<=n;i++)
    {
        cout<<d[i]+ans<<" ";
    }
    fflush(stdout);
}
上一篇:LeetCode 47 全排列II(有重复元素 dfs)


下一篇:Leetcode47.全排列II