zoukankan      html  css  js  c++  java
  • 【CSP模拟赛】Freda的旗帜


    题目描述
      要开运动会了,Freda承担起了制作全校旗帜的工作。旗帜的制作方法是这样的:Freda一共有C种颜色的布条,每种布条都有无数个,你可以认为这些布条的长、宽、厚都相等,只有颜色可能不同。每个旗帜都是由一些布条横向拼接起来的,如图所示,图上所示的是一面红、黄、蓝三种颜色布条拼接的旗帜:

      就不给你看图

      布条数目不同的旗帜显然是不同的。对于布条数目都为T的两面旗帜,如果存在从左到右第i(0<i<=N)个布条颜色不同,那么就认为这两面旗帜是不同的。旋转或翻转后才相同的旗帜被认为是不同的旗帜,比方说,“红黄蓝”和“蓝黄红”被认为是不同的旗帜。有的时候,一些颜色放在相邻的位置上会显得很不好看,比方说红色和绿色放在一起就很不好看。作为一个完美主义者,Freda可不想这样。
      全校共有N个班级,不同的班级必须使用不同的旗帜,Freda也就需要制作N面不同的旗帜了。和谐起见,Freda想让使用布条数目最多的那面旗帜使用的布条数目最少,请你帮助Freda计算一下,在避免了不好看的情况之后,使用布条数目最多的那面旗帜最少要用多少布条。
    输入格式
      第一行两个整数N,C,表示班级的数目和Freda拥有C种颜色的布条。
      接下来C行,每行一个长度为C的字符串,每个字符都为’0’或’1’,第i行第j个字符表示第i种颜色和第j种颜色是否能够相邻。如果能,第i行第j个字符为’1’,否则为’0’.保证第i行第j个字符与第j行第i个字符相同。
    输出格式
      一行一个整数,表示制作了N面不同的旗帜的情况下,使用布条数目最多的那面旗帜最少需要多少布条。
    输入样例
      10 2
      11
      11
    输出样例
      3
    提示
    样例解释
      我们分别制作如下旗帜:
      (1),(2),(1,1),(1,2),(2,1),(2,2),(1,1,1),(1,1,2),(1,2,1),(1,2,2)
      用布条最多的旗帜所用布条为3.
    数据范围与约定
      对于50%的数据,保证0 < N <= 50000.
      对于80%的数据,保证0 < N <= 10^9.
      对于100%的数据,保证0 < N <= 10^18, 0 < C <=10且数据一定有解.

    分析

      这个题也想了半天,其实是因为睡着了

      设f[i][j]表示有旗帜长度为i的时候,第j种颜色开头的方案数,V[i][j]表示i后面是否可以接j

      那么就有

      $$f[i][j]=sum_{k=1}^{c}f[i-1][k]*V[j][k]$$

      发现这个东西可以反手一个矩阵加速闷声发大财,所以对于每一个长度,我们可以很快求出这个长度下的方案数

      而且我们还可以发现长度与方案数是单调递增的,所以可以二分长度,求出这个长度下的方案数的总和,看它是否能大于要求的方案数n

      当然,方案数统计出来可能会炸longlong,我们可以重新定义一个类似longlong的结构体,结构体里除了longlong还要再来一个标记,标记这个数是否超过了n

      Code

    #include<cstdio>
    #include<cstring>
    long long n;int c;
    struct ll{long long num;bool fl;};
    struct node{ll mat[15][15];}a,g;
    ll operator +(ll a,ll b){return (ll){a.num+b.num,a.fl||b.fl||(a.num+b.num>=n)};}
    ll operator *(ll a,ll b)
    {
        if((a.num==0&&!a.fl)||(b.num==0&&!b.fl))return (ll){0,0};
        return (ll){a.num*b.num,a.fl||b.fl||(double(a.num)*double(b.num)>=double(n))};
    }
    node operator *(node a,node b)
    {
        node res;memset(res.mat,0,sizeof res.mat);
        for(int i=1;i<=c+1;i++)for(int j=1;j<=c+1;j++)for(int k=1;k<=c+1;k++)
        res.mat[i][k]=res.mat[i][k]+a.mat[i][j]*b.mat[j][k];
        return res;
    }
    node qp(node a,node g,long long k)
    {while(k){if(k&1)a=a*g;g=g*g;k>>=1;}return a;}
    int main()
    {
        scanf("%lld%d",&n,&c);
        for(int i=1;i<=c;i++)for(int j=1;j<=c;j++)scanf("%1lld",&g.mat[i][j].num);
        for(int i=1;i<=c;i++)a.mat[1][i].num=1,g.mat[i][c+1].num=1;g.mat[c+1][c+1].num=1;
        long long l=1,r=n,mid,ans;
        while(l<=r)
        {
            mid=(l+r)>>1;
            node nw=qp(a,g,mid);ll sum=nw.mat[1][c+1];
            if(sum.fl)ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    LOJ DFS序
    牛客练习赛31 D神器大师泰兹瑞与威穆
    Codeforces Round #487 (Div. 2) C
    Manthan, Codefest 18 (rated, Div. 1 + Div. 2) C D
    [Windows Server 2003] 还原SQL Server数据库
    [Windows Server 2008] 查看PHP详细错误信息
    [Windows Server 2008] 安装网站伪静态
    网站Gzip压缩
    [Windows Server 2008] SQL Server 2008 数据库还原方法
    [Windows Server 2008] 安装Apache+PHP+MySQL
  • 原文地址:https://www.cnblogs.com/firecrazy/p/11792190.html
Copyright © 2011-2022 走看看