AtCoder Beginner Contest 157

A Duplex Printing

#include<bits/stdc++.h>
using namespace std;
const int N=10;
int n;
int main()
{
    cin>>n;
    cout<<n/2+n%2<<endl;
}

B Bingo

#include<bits/stdc++.h>
using namespace std;
const int N=10;
int n,m,a[N][N];
bool vis[N][N];
bool judge()
{
    for(int i=1;i<=3;i++)
    {
        bool flag=true;
        for(int j=1;j<=3;j++)
            if(!vis[i][j]) flag=false;
        if(flag) return flag;
    }
    for(int j=1;j<=3;j++)
    {
        bool flag=true;
        for(int i=1;i<=3;i++)
            if(!vis[i][j]) flag=false;
        if(flag) return flag;
    }
    return vis[1][1]&&vis[2][2]&&vis[3][3]||vis[1][3]&&vis[2][2]&&vis[3][1];
}
int main()
{
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++) scanf("%d",&a[i][j]);
    scanf("%d",&n);
    while(n--)
    {
        int x;scanf("%d",&x);
        for(int i=1;i<=3;i++)
            for(int j=1;j<=3;j++)
            if(a[i][j]==x) vis[i][j]=true;
    }
    if(judge()) printf("Yes\n");
    else printf("No\n");
}

C Guess The Number
模拟

#include<bits/stdc++.h>
using namespace std;
const int N=10;
int n,m,a[N],b[N];
bool judge(int x)
{
    int tot=0,s[N];
    while(x)
    {
        s[++tot]=x%10;x/=10;
    }
    if(tot==0) s[++tot]=0;
    if(tot!=n) return false;
    reverse(s+1,s+1+tot);
    for(int i=1;i<=m;i++)
        if(s[a[i]]!=b[i]) return false;
    return true;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%d%d",&a[i],&b[i]);
    for(int i=0;i<=999;i++)
        if(judge(i))
    {
        printf("%d\n",i);return 0;
    }
    printf("-1\n");
}

D Friend Suggestions
并查集(我莫名的写了一个bitset??)。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,k,f[N],ans[N];
int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);}
vector<int>v[N],e[N];
bitset<N>b1,b2;
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
        u=getf(u);v=getf(v);
        if(u==v) continue;
        f[u]=v;
    }
    for(int i=1;i<=k;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for(int i=1;i<=n;i++)
        v[getf(i)].push_back(i);
    for(int i=1;i<=n;i++)
        if(f[i]==i)
    {
        b1.reset();
        for(int u:v[i]) b1[u]=1;
        for(int u:v[i])
        {
            b2.reset();
            for(int x:e[u]) b2[x]=1;
            b2[u]=1;
            b2=~b2;
            ans[u]=(b2&b1).count();
        }
    }
    for(int i=1;i<=n;i++)
        printf(i==n?"%d\n":"%d ",ans[i]);
}

E Simple String Queries
a − z a-z az 0 − 25 0-25 025表示,再把他们用二进制位表示,就可以用或运算和线段树单点修改区间查询解决这道问题,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,q,t[N<<2],lev[N];
char s[N];
void update(int k)
{
    t[k]=t[k<<1]|t[k<<1|1];
}
void build(int l,int r,int k)
{
    if(l==r)
    {
        lev[l]=k;
        t[k]=1<<(s[l]-'a');return;
    }
    int m=l+r>>1;
    build(l,m,k<<1);build(m+1,r,k<<1|1);
    update(k);
}
void fix(int x,char c)
{
    if(s[x]==c) return;
    s[x]=c;
    x=lev[x];
    t[x]=1<<(c-'a');
    while(x>>=1) update(x);
}
int query(int l,int r,int k,int x,int y)
{
    if(r<x||l>y) return 0;
    if(l>=x&&r<=y) return t[k];
    int m=l+r>>1;
    return query(l,m,k<<1,x,y)|query(m+1,r,k<<1|1,x,y);
}
int main()
{
    scanf("%d%s",&n,s+1);
    build(1,n,1);
    scanf("%d",&q);
    while(q--)
    {
        int opt;scanf("%d",&opt);
        if(opt==1)
        {
            int x;char c;
            scanf("%d %c",&x,&c);
            fix(x,c);
        }
        else
        {
            int l,r;scanf("%d%d",&l,&r);
            printf("%d\n",__builtin_popcount(query(1,n,1,l,r)));
        }
    }
}

F - Yakiniku Optimization Problem
首先,容我介绍一下余弦定理,对于三角形三边 a , b , c a,b,c a,b,c,设与每个边相对的角为 A , B , C A,B,C A,B,C,有如下定理(把 c o s cos cos写成 C o s Cos Cos以便于区分):
c 2 = a 2 + b 2 − 2 a b C o s C c^2=a^2+b^2-2abCosC c2=a2+b22abCosC
a 2 = b 2 + c 2 − 2 b c C o s A a^2=b^2+c^2-2bcCosA a2=b2+c22bcCosA
b 2 = a 2 + c 2 − 2 a c C o s C b^2=a^2+c^2-2acCosC b2=a2+c22acCosC
现在,让我介绍一下如何求两个圆的交点,对于两个相交的圆(如下图):
设两个圆的圆心距为 d d d,那么 r 1 , r 2 , d r1,r2,d r1,r2,d以两个圆心和一个交点为顶点构成一个三角形。
再根据上面的定理,我们可以求出角 a a a的大小。
设两个圆的圆心分别为 c 1 , c 2 c1,c2 c1,c2,我们可以用 a t a n 2 atan2 atan2函数求出向量 c 1 − > c 2 c1->c2 c1>c2 x x x轴的夹角,设这个夹角为 t t t,那么 r 1 r1 r1这条边的单位向量为 c o s ( t + a ) , s i n ( t + a ) cos(t+a),sin(t+a) cos(t+a),sin(t+a),第一个交点为 c 1 + r 1 ( c o s ( t + a ) , s i n ( t + 2 ) ) c1+r1(cos(t+a),sin(t+2)) c1+r1(cos(t+a),sin(t+2)),那么底下那条边的单位向量为 c o s ( t − a ) , s i n ( t − a ) cos(t-a),sin(t-a) cos(ta),sin(ta),同理,两个交点就可以求出来了。
在这里插入图片描述
现在,让我们回到这个问题,假设我们的答案是 T T T,答案的端点是 X , Y X,Y X,Y,那么说明有 k k k个点满足 c k s q r t ( d i s ( x k , y k , X , Y ) ) < = T c_ksqrt(dis(x_k,y_k,X,Y))<=T cksqrt(dis(xk,yk,X,Y))<=T,把这个式子移一下 s q r t ( d i s ( x k , y k , X , Y ) ) < = T / c k sqrt(dis(x_k,y_k,X,Y))<=T/c_k sqrt(dis(xk,yk,X,Y))<=T/ck,把两个平方一下,可以发现这是一个圆的方程。
那么问题可以转换为:有 n n n个圆,第 i i i个圆的圆心为 x i , y i x_i,y_i xi,yi,半径为 T / c i T/c_i T/ci,是否存在一片区域,被至少 k k k个点覆盖。显然,这个公共区域一定满足有一个点是两个圆的交点,而答案 T T T具有单调性,所以,我们可以二分答案,再根据以上求圆交的方法,枚举两个圆即可。
时间复杂度 O ( n 4 ) O(n^4) O(n4)(因为我的写法二分的次数和 n n n同阶)。
此外,注意判断一下相离和内含的情况,内含时可以认为公共区域一定时某个圆的圆心。

#include<bits/stdc++.h>
#define mems(a,x) memset(a,x,sizeof(a))
#define first fi
#define second se
using namespace std;
typedef long long ll;
const int mod=1e9+7,MS=105,N=66;
const double eps=1e-8;
ll inv(ll x){return x==1?x:(mod-mod/x)*inv(mod%x)%mod;}
ll inv(ll x,ll mod){return x==1?x:(mod-mod/x)*inv(mod%x,mod)%mod;}
ll qpow(ll a,ll n){ll ans=1;while(n){if(n&1) ans=ans*a%mod;a=a*a%mod;n>>=1;}return ans;}
ll mul(ll a,ll b){ll ans=0;while(b){if(b&1) ans=(ans+a)%mod;a=(a+a)%mod;b>>=1;};return ans;}
ll qpow(ll a,ll n,ll mod){ll ans=1;while(n){if(n&1) ans=ans*a%mod;a=a*a%mod;n>>=1;}return ans;}
ll mul(ll a,ll b,ll mod){ll ans=0;while(b){if(b&1) ans=(ans+a)%mod;a=(a+a)%mod;b>>=1;};return ans;}
struct vec
{
    double x,y;
    vec(double x=0,double y=0):x(x),y(y){}
    vec operator+(const vec&o)const{ return vec(x+o.x,y+o.y);}
    vec operator-(const vec&o)const{ return vec(x-o.x,y-o.y);}
    double operator*(const vec&o)const{ return x*o.x+y*o.y;}
    double operator^(const vec&o)const{ return x*o.y-y*o.x;}
    vec operator/(const double&o)const{ return vec(x/o,y/o);}
    vec operator*(const double&o)const{ return vec(x*o,y*o);}
    void sc(){scanf("%lf%lf",&x,&y);}
    double len(){return sqrt(x*x+y*y);}
};
struct Mat
{
    ll a[MS][MS];
    int n,m;
    Mat(int n=0,int m=0):n(n),m(m) { mems(a,0);}
    Mat operator*(const Mat&B)const
    {
        Mat C(n,B.m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=B.m;j++)
                for(int k=1;k<=m;k++)
                C.a[i][j]=(C.a[i][j]+a[i][k]*B.a[k][j])%mod;
        return C;
    }
};
int n,k;
vec a[N];
double c[N];
vec s1,s2;
vec polar(double a,double r){return vec(cos(r)*a,sin(r)*a);}
bool intersect(vec c1,vec c2,double r1,double r2)
{
    double d=(c1-c2).len();
    if(d-eps>r1+r2||d<=r1||d<=r2) return false;
    //相离或内含
    double a=acos((r1*r1+d*d-r2*r2)/(2*r1*d));
    double t=atan2(c2.y-c1.y,c2.x-c1.x);
    s1=c1+polar(r1,t-a);
    s2=c1+polar(r1,t+a);
    return true;
}
bool judge(double T)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            if(!intersect(a[i],a[j],T/c[i],T/c[j])) continue;
            int x=0,y=0;
            for(int k=1;k<=n;k++)
            {
                if(c[k]*(s1-a[k]).len()<=T+eps) x++;
                if(c[k]*(s2-a[k]).len()<=T+eps) y++;
            }
            if(x>=k||y>=k) return true;
        }
        int x=0;
        for(int j=1;j<=n;j++)
            if(c[j]*(a[i]-a[j]).len()<=T+eps) x++;
        if(x>=k) return true;
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        a[i].sc(),scanf("%lf",&c[i]);
    double l=0,r=200000;
    for(int i=1;i<=50;i++)
    {
        double m=(l+r)/2;
        if(judge(m)) r=m;
        else l=m;
    }
    printf("%.10f\n",(l+r)/2);
}
/*
|? ?| * |f(x)  | == |f(x+1)|
|? ?|   |f(x-1)|    |f(x)  |
f(x)=af(x-1)+bf(x-2)
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值