codeforces #549 Looksery Cup 部分题解

来源:互联网 发布:淘宝下拉选93es.com 编辑:程序博客网 时间:2024/05/20 05:46

掉Rating快乐~~

A.Face Detection

题目大意:给定一个nm的矩阵,求有多少22的子矩形满足单词“face”的每个字母在矩形中恰好出现一次

签到题

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 55using namespace std;int n,m,ans;char map[M][M];int main(){    int i,j;    cin>>n>>m;    for(i=1;i<=n;i++)        scanf("%s",map[i]+1);    for(i=1;i<n;i++)        for(j=1;j<m;j++)        {            char s[4]={map[i][j],map[i+1][j],map[i][j+1],map[i+1][j+1]};            sort(s,s+4);            if(s[0]=='a'&&s[1]=='c'&&s[2]=='e'&&s[3]=='f')                ++ans;        }    return cout<<ans<<endl,0;}

B.Looksery Party

题目大意:给定一个nn的01矩阵A,满足Ai,i=1,以及一个1n的行向量B
输出一个{1,2,...,n}的子集S,令C=iSAi,要求CiBi

令集合T为当前满足Ci=Bi的所有i的集合,然后进行如下操作:
while(T非空)
{
任选xT,将xT集合删除,加入集合S
CC+Ax
对于所有Ax,y=1,Cy=By,将y加入T集合
}
由于每个元素最多进入T集合一次,因此S中一定不会有重复
这个题的核心在于Ai,i=1

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 110using namespace std;int n,a[M];char map[M][M];int q[M],r,h;int stack[M],top;int main(){    int i,j;    cin>>n;    for(i=1;i<=n;i++)        scanf("%s",map[i]+1);    for(i=1;i<=n;i++)    {        scanf("%d",&a[i]);        if(!a[i]) q[++r]=i;    }    while(r!=h)    {        int x=q[++h];        stack[++top]=x;        for(i=1;i<=n;i++)            if( map[x][i]=='1' && !--a[i] )                q[++r]=i;    }    cout<<top<<endl;    for(i=1;i<=top;i++)        printf("%d\n",stack[i]);    return 0;}

C.The Game Of Parity

题目大意:给定n个点,每个点有点权,两个人轮流取,每次只能取走一个点,当剩余k个点时游戏结束,此时若剩余奇数个点则先手获胜,否则后手获胜,求先手是否必胜

大讨论,注意n=k的情况

#include <cstdio>int main(){    puts("I haven't written this problem. >w<");    return 0;}

D.Haar Features

题目大意:给定一个矩阵,每个点有一种颜色(黑/白)和一个点权(未给出),求最少计算矩阵的多少个前缀和可以计算出所有黑点的点权和和所有白点的点权和

题目等价于每次可以选择一个前缀矩形,加上任意值,求最少多少次操作后可以使所有黑点都是1,白点都是1
O(n2m2)大模拟即可

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 110using namespace std;int n,m,ans;char map[M][M];int a[M][M];int main(){    int i,j,k,l;    cin>>n>>m;    for(i=1;i<=n;i++)        scanf("%s",map[i]+1);    for(i=n;i;i--)        for(j=m;j;j--)            if(a[i][j]!=(map[i][j]=='B'?1:-1) )            {                int temp=(map[i][j]=='B'?1:-1)-a[i][j];                ans++;                for(k=1;k<=i;k++)                    for(l=1;l<=j;l++)                        a[k][l]+=temp;            }    cout<<ans<<endl;    return 0;}

E.Sasha Circle
题目大意:给定一些红点和一些蓝点,求是否存在一个圆能将红点和蓝点完全分开

论文题。

#include <cstdio>#include <algorithm>int main(){    srand(23333333);    puts(rand()&1?"YES":"NO");}

F:Yura and Developers

题目大意:给定一个长度为n的序列,求有多少区间满足区间和区间最大值0( mod k)

每次选择区间最大值进行分治,可以得到一棵树形结构
用map启发式合并可以做到O(nlog2n)
用数组可以做到O(nlogn)
具体写法看代码把我也说不清楚

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 300300using namespace std;struct Array{    int a[1001001],tim[1001001],T;    void Initialize()    {        ++T;    }    int& operator [] (int x)    {        if(tim[x]!=T)            tim[x]=T,a[x]=0;        return a[x];    }}cnt;int n,k;long long ans;int a[M],sum[M],son[M][2];int stack[M],top;void Divide_And_Conquer(int x,int l,int r){    int i;    if(!x) return ;    if( x-l < r-x )    {        Divide_And_Conquer(son[x][0],l,x-1);        cnt.Initialize();        Divide_And_Conquer(son[x][1],x+1,r);        cnt[sum[x]]++;        for(i=l-1;i<=x-1;i++)            ans+=cnt[(sum[i]+a[x])%k];        cnt[sum[x]]--;        for(i=l;i<=x;i++)            cnt[sum[i]]++;    }    else    {        Divide_And_Conquer(son[x][1],x+1,r);        cnt.Initialize();        Divide_And_Conquer(son[x][0],l,x-1);        cnt[sum[l-1]]++;        for(i=x;i<=r;i++)            ans+=cnt[(sum[i]+k-a[x]%k)%k];        cnt[sum[l-1]]--;        for(i=x;i<=r;i++)            cnt[sum[i]]++;    }}int main(){    int i;    cin>>n>>k;    for(i=1;i<=n;i++)        scanf("%d",&a[i]);    for(i=1;i<=n;i++)        sum[i]=(sum[i-1]+a[i])%k;    for(i=1;i<=n;i++)    {        while( top && a[stack[top]]<a[i] )        {            if( top>=2 && a[stack[top-1]]<a[i] )                son[stack[top-1]][1]=stack[top];            else                son[i][0]=stack[top];            stack[top--]=0;        }        stack[++top]=i;    }    for(i=1;i<top;i++)        son[stack[i]][1]=stack[i+1];    Divide_And_Conquer(stack[1],1,n);    cout<<ans-n<<endl;    return 0;}

G:Happy Line

题目大意:给定一个序列,每次你可以选择两个相邻的数,将左边的数1,右边的数+1,然后交换这两个数
问能否通过操作使得序列单调不减

容易发现,每个元素的大小+位置是不变的
要求最终的序列单调不减,那么位置递增,大小不减,故大小+位置递增
只需要按照大小+位置排个序,然后判断相邻两项是否相同即可

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 200200using namespace std;int n,a[M],b[M];bool Compare(int x,int y){    return x+a[x] < y+a[y] ;}int main(){    int i;    cin>>n;    for(i=1;i<=n;i++)        scanf("%d",&a[i]);    for(i=1;i<=n;i++)        b[i]=i;    sort(b+1,b+n+1,Compare);    for(i=1;i<=n;i++)        if(a[b[i]]+b[i]-i<0)            return puts(":("),0;    for(i=1;i<n;i++)        if(a[b[i]]+b[i]==a[b[i+1]]+b[i+1])            return puts(":("),0;    for(i=1;i<=n;i++)        printf("%d%c",a[b[i]]+b[i]-i,i==n?'\n':' ');    return 0;}

H:Degenerate Matrix

题目大意:给定一个22的矩阵A,定义||A||A中所有元素绝对值的最大值,求一个行列式为022矩阵B满足||AB||最小

二分答案x
A=(a   bc   d),B=(a   bc   d)
那么:
a[ax,a+x],...
现在要求ad=bc
我们知道若x[l1,r1],y[l2,r2],那么xy[min{l1l2,l1r2,r1l2,r1r2},max{...}]
我们只需要判断ad所在区间与bc所在区间有没有交即可

#include <cstdio>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>#define EPS 1e-16using namespace std;typedef __float128 ld;struct Interval{    ld l,r;    Interval() {}    Interval(ld _,ld __):        l(_),r(__) {}    friend Interval operator * (const Interval &i1,const Interval &i2)    {        ld a1=i1.l*i2.l;        ld a2=i1.l*i2.r;        ld a3=i1.r*i2.l;        ld a4=i1.r*i2.r;        return Interval(min(min(a1,a2),min(a3,a4)),max(max(a1,a2),max(a3,a4)));    }    bool In_Interval(ld x) const    {        return x >= l && x <= r ;    }    friend bool Have_Intersection(const Interval &i1,const Interval &i2)    {        return i1.In_Interval(i2.l) || i1.In_Interval(i2.r) || i2.In_Interval(i1.l) ;    }};long double a,b,c,d;bool Judge(ld x){    Interval _a(a-x,a+x);    Interval _b(b-x,b+x);    Interval _c(c-x,c+x);    Interval _d(d-x,d+x);    Interval temp1=_a*_d,temp2=_b*_c;    return Have_Intersection(temp1,temp2);}long double Bisection(){    ld l=0,r=1e9;    for(int i=1;i<=1000;i++)    {        ld mid=(l+r)/2;        if( Judge(mid) )            r=mid;        else            l=mid;    }    return (l+r)/2;}int main(){    cin>>a>>b>>c>>d;    cout<<fixed<<setprecision(20)<<Bisection()<<endl;}
0 0
原创粉丝点击