2020牛客暑期多校训练营(第三场)D、E、F

Points Construction Problem

2020牛客暑期多校训练营(第三场)D、E、F_第1张图片

解法:

首先判断无解的情况:

1.易得m为奇数时无解

2.大于最大组数4*n时无解

3.小于最小组数时无解  :

2020牛客暑期多校训练营(第三场)D、E、F_第2张图片

接下来构造合法情况:

采用不断从最小组合情况里从上到下的顺序不断拆出,放到遥远处,使得组合数为m

每次拆一个正方形组合数加num

当该正方形的四个方向有2个正方形相邻时,num=4;

当该正方形的四个方向只有1个正方形相邻时,num=2;

当出现还差2个组合数时,需要特殊处理:

假设现在轮到( i , j )位置正方形拆开时,若增加的num=2 ,则放到遥远处

若num=4 ,则会多加2个组合,可以构造放到(1,1)位置的左边,就可以时增加的num降至2

即可

#include
using namespace std;
int t;
int n,m;
int aa,bb;
int getmin(int a)//最小组合数 
{
    int ans=1e9;
    for(int i=1;i<=a;i++)
    {
        int j=(int)ceil((double)a/i);
        if(i+j<=ans&&i&&j&&abs(i-j)<=1)
        {
            aa=i;
            bb=j;
            if(aa>bb) swap(aa,bb);
        }
        ans=min(ans,i+j);
    }
    return 2*ans;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        if(m%2||m>4*n||getmin(n)>m)//无解 
        {
            printf("No\n");
        }
        else
        {
            int mi=getmin(n);//最小组合数 
            vector > v;
            vector > u;
            int num=n;
            for(int i=1;i<=aa&#i++)
            {
                for(int j=1;j<=bb&#j++)
                {
                    v.push_back(make_pair(i,j));//按最小的方式构造 再拆开 
                    num--;
                }
            }
            int now=n-1;
            int flag=1;
            while(m - mi >= 4&&now>=0)
            {
                int x=v[now].first;
                int y=v[now].second;
                if(y==1||x==1)
                {
                	mi+=2;
				}
				else mi+=4;
                u.push_back(make_pair(flag,100000000));//放到遥远处 
                now--;
                flag+=2;
                if(mi==m) break;
            }
            if(m-mi==2)
            {
				int x=v[now].first;
                int y=v[now].second;
                if(y==1||x==1)
                {
                	u.push_back(make_pair(flag,100000000));//放到遥远处
				}
				else
				{
					u.push_back(make_pair(0,1));//放到(1,1)旁边 
				}
				now--;
            }
            puts("Yes");
            for(int i=0;i

Fraction Construction Problem

2020牛客暑期多校训练营(第三场)D、E、F_第3张图片

解法:

 

情况1:先考虑能不能通过构造出c,d,e,f  我们可以构造出一左边分数减去右边分数就是a/b,例如:\frac{a+1}{b}-\frac{1}{b}=\frac{a}{b}

但是由于存在限制条件d,f

A=a/gcd 、B=b/gcd\frac{A+1}{B}-\frac{1}{B}=\frac{A}{B}  此时B

情况2:当不满足情况1时,说明一定gcd(a,b)==1 ,若b==1或b为素数(相异质因数),那么无解 -1 -1 -1 -1

情况3:当d*f=b,且d,f互质 通分得:

再拓展gcd即可

#include
#define ll long long
using namespace std;
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(!b)
    {
        d=a;
        x=1;
        y=0;
    }
    else
    {
        exgcd(b,a%b,d,y,x);   
        y-=x*(a/b);
    }
}
   
ll mod_count(ll a,ll c,ll b)//求解模线性方程ax=c(mod b)
{
    ll x,y;
    ll gcd;
    exgcd(a,b,gcd,x,y);
    ll aa=a;
    ll bb=b;
    while(x<=0||y>=0)//注意x,y 符号 
    {
        x+=bb;
        y-=aa;
    }
    x=(x*(c/gcd));//次题gcd一定为1 
    y=(y*(c/gcd));
    printf("%lld %lld %lld %lld\n",x,bb,-1*y,aa);
    return x;
}
  
const int N=2e6+5;
int mark[N];
int prim[N];
int cnt;
void initial()
{
    cnt=0;
    for (int i=2 ; i

Operating on a Graph

2020牛客暑期多校训练营(第三场)D、E、F_第4张图片

2020牛客暑期多校训练营(第三场)D、E、F_第5张图片

#include
using namespace std;
int fa[800005];
int color[800005];
list L[800005];
vector G[800005];
int find(int x)
{
    if(fa[x]==x) return fa[x];
    else return fa[x]=find(fa[x]);
}
int main()
{
    int t;    
    scanf("%d",&t);


    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++)
        {
            fa[i]=i;
            L[i].clear();
            G[i].clear();
            L[i].push_back(i);
        }
        for(int i=0;i

 

你可能感兴趣的:(2020牛客暑期多校训练营(第三场)D、E、F)