2021年度训练联盟热身训练赛第一场

传送门:https://ac.nowcoder.com/acm/contest/12606#question

 

A题 Weird Flecks, But OK

题解:计算几何 最小圆覆盖问题

B题 Code Names

题解:建图+匈牙利算法   最大团=补图的最大独立集  最大独立集=点数-最大匹配/2

C题 New Maths

题解:搜索

D Some Sum

题解:签到题  暴力

E Early Orders

题解:栈模拟

F Pulling Their Weight

题解:签到题

G Birthday Paradox

题解:组合数学

H On Average They're Purple

题解:最短路

J This Ain't Your Grandpa's Checkerboard

题解:模拟

 

A把点投到三个平面,做三次最小点覆盖。 

#include<bits/stdc++.h>
using namespace std;

#define N 5210
#define pf(x) ((x)*(x))
#define eps 1e-6
int n;
double x[N],y[N],z[N];
double R;
struct point
{
    double x,y;
}p[N],O;
//求两点间的距离 
double getdis(point a,point b)
{
    return sqrt(pf(a.x-b.x)+pf(a.y-b.y));
}
//三点定一圆的圆心 
point getO(point p1,point p2,point p3)
{
    point res; 
    double a=p2.x-p1.x;
    double b=p2.y-p1.y;
    double c=p3.x-p2.x;
    double d=p3.y-p2.y;
    double e=pf(p2.x)+pf(p2.y)-pf(p1.x)-pf(p1.y);
    double f=pf(p3.x)+pf(p3.y)-pf(p2.x)-pf(p2.y);
    res.x=(f*b-e*d)/(c*b-a*d)/2.0; 
    res.y=(a*f-e*c)/(a*d-b*c)/2.0; 
    return res; 
}

void slove()
{
    O=p[1];R=0;
    for(int i=1;i<=n;i++)
    {
        if(getdis(p[i],O)-R>eps)
        {
            O=p[i];R=0;
            for(int j=1;j<i;j++)
            {
                if(getdis(p[j],O)-R>eps)
                {
                    O=(point){(p[i].x+p[j].x)/2.0,(p[i].y+p[j].y)/2.0};
                    R=getdis(p[i],p[j])/2.0;
                    for(int k=1;k<j;k++)
                    {
                        if(getdis(p[k],O)-R>eps)
                        {
                            O=getO(p[i],p[j],p[k]);
                            R=getdis(p[i],O);
                        }
                    }
                }
            }
        }
    }
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>x[i]>>y[i]>>z[i];
    double ans=100000;
    for(int i=1;i<=n;i++) p[i].x=x[i],p[i].y=y[i];
    random_shuffle(p+1,p+1+n);
    slove();
    if(ans-R>eps) ans=R;
    for(int i=1;i<=n;i++) p[i].x=x[i],p[i].y=z[i];
    random_shuffle(p+1,p+1+n);
    slove();
    if(ans-R>eps) ans=R;
    for(int i=1;i<=n;i++) p[i].x=y[i],p[i].y=z[i];
    random_shuffle(p+1,p+1+n);
    slove();
    if(ans-R>eps) ans=R;
    printf("%.10f",2*ans);
}
View Code

 B

将不能通过一次交换就变成对方的字符串连线,发现答案是最大完全子图

建立上图的补图,即 将能通过交换就变成对方的字符串连线建图,求最大匹配数。

最大完全子图=补图的最大独立集=点数-最大匹配/2

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1000001
using namespace std;

int n,sumedge,cnt;
int head[maxn],vis[maxn],match[maxn];
string s[maxn];

struct Edge{
    int x,y,nxt;
    Edge(int x=0,int y=0,int nxt=0):
        x(x),y(y),nxt(nxt){}
}edge[maxn<<1];

void add(int x,int y){
    edge[++sumedge]=Edge(x,y,head[x]);
    head[x]=sumedge;
}

bool pipei(int x){
    for(int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].y;
        if(vis[v]==0){
            vis[v]=1;
            if(!match[v]||pipei(match[v])){
                match[v]=x;return true;
          }
       }
    }return false;
}

void INit()
{
    scanf("%d",&n);
    int len;
    for(int i=1;i<=n;i++) cin>>s[i];
    len=s[1].length();
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            int js=0;
            for(int k=0;k<len;k++)
            {
                if(s[i][k]!=s[j][k]) js++;
            } 
            if(js<3) 
            {
                add(i,j);
                add(j,i);
            //    cout<<i<<"--"<<j<<endl;
            } 
        } 
    }
}
int main()
{
    INit();
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(pipei(i)) ans++;
     } 
     cout<<n-ans/2;
    return 0;
}
View Code

C

搜索 枚举a的每一位

#include<bits/stdc++.h>
using namespace std;

#define N 55

int len;
int a[N];
char s[N];
bool flag;

void dfs(int now)
{
    if(now>len&&!flag)
    {
        int gg=(len+1)/2;
        flag=1;
        for(int i=1;i<=gg;i++)
        {
            cout<<a[i];
        }
        return ;
    }
    for(int i=0;i<=9;i++)
    {
        a[now]=i;
        int sum=0;
        for(int j=1;j<=now;j++)
        {
            sum=sum+a[j]*a[now-j+1];
        }
        if(sum%10==s[now]-'0') dfs(now+1);
    }
}

int main()
{
    scanf("%s",s+1);
    len=strlen(s+1);
    if(len%2==0)
    {
        cout<<"-1\n";
        return 0; 
    }
    dfs(1);
    if(!flag)
    {
        cout<<"-1";
    }
    return 0;
}
View Code

D

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin>>n;
    bool ou=0,ji=0;
    for(int i=1;i<=100;i++)
    {
        int sum=0;
        for(int j=i;j<=i+n-1;j++)
        {
            sum=sum+j;
        }
        if(sum%2==0)ou=1;
        if(sum%2==1)ji=1;
    } 
    if(ou==1&&ji==1) cout<<"Either";
    if(ou==1&&ji==0) cout<<"Even";
    if(ou==0&&ji==1) cout<<"Odd"; 
    return 0;
} 

/*

*/ 
View Code

E

维护一个栈

1)当前数在栈中,不做操作

2)当前数不在栈中时

若当前数比栈顶小,且栈顶的数在后面还会再出现,栈顶的数出栈,当前数进栈

 代码队友写的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
int s[200050]={0};
int flag[200050]={0};
stack<int>st;
int vis[200050]={0};
int ans[200050]={0};
int main()
{
    int n,k;
    cin>>n>>k;
    int i;
    for(i=0;i<n;i++)
    {
        cin>>s[i];
    }
    int len=n;
    for(int i=0;i<len;i++)
    {
        flag[s[i]]++;//计算数量 
    }
    st.push(s[0]);
    vis[s[0]]=1;//标记 
    flag[s[0]]--;
    for(int i=1;i<len;i++)
    {
        flag[s[i]]--;
        if(vis[s[i]])//在栈内,就不用操作,直接下一个元素 
            continue;
        while(!st.empty()&&st.top()>s[i]&&flag[st.top()]>0)//s[i]比栈顶元素小且后面还有栈顶元素,则出栈 
        {
            vis[st.top()]=0;
            st.pop();
        }
        st.push(s[i]);//没有标记的进栈 
        vis[s[i]]=1;    
    }    
    int sum=0;
    while(!st.empty())
    {
        if(ans[sum]!=st.top())
        {
            ans[sum++]=st.top();
        }
        st.pop();
    }
    for(int i=sum-1;i>=0;i--)//倒序输出 
    {
        if(ans[i]!=ans[i+1])
        {
            cout<<ans[i]<<' ';
        }
    }
} 
View Code

F

略 队友代码

#include<iostream>
using namespace std;
long long n,i,x,sum1=0,sum2=0,a[20005],t,u;

int main()
{cin.tie(0);ios::sync_with_stdio(false);
    cin>>n;
    for(i=1;i<=n;i++)
    {
        cin>>x;
        sum1+=x;
        a[x]++;
    }
    for(i=1;i<=20000;i++)
    {
        if(a[i]>0)
        {
            if(a[i]%2==0) {t=sum2+a[i]/2*i;if(t*2==sum1) {cout<<i<<endl;return 0;}}
            else
            {
                t=sum2;
                u=sum1-sum2-a[i]*i;
                if(t==u){cout<<i<<endl;return 0;}
            }
        }else
        {
            t=sum2;
            if(t*2==sum1) {cout<<i<<endl;return 0;}
        }
        sum2+=a[i]*i;
    }
    
    return 0;
}
View Code

 

G

 

把上面式子拆开算就行
#include<bits/stdc++.h>
using namespace std;
#define N 520

int n,m;
double Log[100000];
int d[N],c[N];
double ans;

double log10(int x)
{
    return log(x)/log(10);
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<100000;i++) Log[i]=Log[i]+Log[i-1]+log10(i);
    for(int i=1;i<=n;i++) cin>>c[i],d[c[i]]++,m+=c[i];
    ans=Log[365]-Log[365-n]-Log[n]+Log[m]+Log[n]-m*log10(365);
    for(int i=1;i<=n;i++) ans=ans-Log[c[i]];
    for(int i=1;i<=100;i++) ans=ans-Log[d[i]];
    printf("%.15lf",ans);
    return 0;
}
View Code

H

发现最小颜色改变次数为 1到n的最短路径长度-1

求最短路用的优化后的狄杰斯特拉

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define N 100008
using namespace std;

int n,m,s;

int sumedge;

int head[N],dis[N],vis[N];

struct Edge{
    int x,y,z,nxt;
    Edge(int x=0,int y=0,int z=0,int nxt=0):
        x(x),y(y),z(z),nxt(nxt){}
}edge[N*2];

struct node{
    int x,dis;
    bool operator < (node a) const{
        return dis>a.dis;
    }
};

priority_queue<node>q;

void add(int x,int y,int z){
    edge[++sumedge]=Edge(x,y,z,head[x]);
    head[x]=sumedge;
}

void dijikstra(int x){
    while(!q.empty())q.pop();
    memset(dis,0x3f,sizeof(dis));
    dis[x]=0;
    q.push((node){x,0});
    while(!q.empty()){
        node now=q.top();q.pop();
        if(vis[now.x])continue;
        vis[now.x]=true;
        for(int i=head[now.x];i;i=edge[i].nxt){
            int v=edge[i].y;
            if(dis[v]>dis[now.x]+edge[i].z){
                dis[v]=dis[now.x]+edge[i].z;
                q.push((node){v,dis[v]}); 
            }
        }
    } 
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y,1);
        add(y,x,1);
    }
    dijikstra(1);
    cout<<dis[n]-1;
    return 0;
}
View Code

J

简单模拟

#include<bits/stdc++.h>
using namespace std; 

int n;
char s[25][25];

bool check1()
{
    int cnt1=0,cnt2=0,cntb=0;
    for(int j=1;j<=n;j++)
    {
        if(s[1][j]=='B') 
        {
            cnt1++,cntb++;
            if(cnt2>=3) return 0;
            cnt2=0;
        }
        else 
        {
            if(cnt1>=3) return 0;
            cnt1=0;
            cnt2++;
        }
    } 
    if(cntb==n) return 0;
    int jsb=0;
    for(int i=1;i<=n;i++)
    {
        jsb=0;cnt1=0;cnt2=0;
        for(int j=1;j<=n;j++)
        {
            if(s[i][j]=='B') 
            {
                cnt1++,jsb++;
                if(cnt2>=3) return 0;
                cnt2=0;
            }
            else
            {
                if(cnt1>=3) return 0;
                cnt1=0;cnt2++;
            } 
        }
        if(jsb!=cntb) return 0;
    }
    return 1;
}

bool check2()
{
    int cnt1=0,cnt2=0,cntb=0;
    for(int j=1;j<=n;j++)
    {
        if(s[j][1]=='B') 
        {
            cnt1++,cntb++;
            if(cnt2>=3) return 0;
            cnt2=0;
        }
        else 
        {
            if(cnt1>=3) return 0;
            cnt1=0;
            cnt2++;
        }
    } 
    if(cntb==n) return 0;
    int jsb=0;
    for(int i=1;i<=n;i++)
    {
        jsb=0;cnt1=0;cnt2=0;
        for(int j=1;j<=n;j++)
        {
            if(s[j][i]=='B') 
            {
                cnt1++,jsb++;
                if(cnt2>=3) return 0;
                cnt2=0;
            }
            else
            {
                if(cnt1>=3) return 0;
                cnt1=0;cnt2++;
            } 
        }
        if(jsb!=cntb) return 0;
    }
    return 1;
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>(s[i]+1);
    }
    if(check1()==0)
    {
        cout<<"0\n";
        return 0;
    }
    if(check2()==0)
    {
        cout<<"0\n";
        return 0;
    }
    cout<<"1";
    return 0;
}
View Code

 

posted @ 2021-03-10 17:04  ANhour  阅读(116)  评论(0)    收藏  举报