• 3.17日常小测


    T1:求一个有多少个不同的长度为n的序列满足|ai-i|<=k,n<=1e9,k<=4。

    题解:一开始打了个表,发现k=1的时候是个斐波那契,再看其他情况,感觉很有规律的样子,于是就开始了2个小时找规律的不归路。

    其实题目已经很明显了,n为1e9,不是找规律的O(1)就是矩阵快速幂的三方log。这题看到k这么小,第一反应就应该是状压DP。考虑用一个2*k+1位的二进制数来表示左右的占用情况,然后转移。

    不过这样矩阵大小是256的,这还跑不过去。我们再看,发现,状态一定是有k个位置为1(被占)的,那么就是C(9,4)=126的状态数,这样就很好了,可以直接预处理出转移给每个状态标号然后矩阵快速幂DP了。

    为什么状态一定要有k个1呢?我们这么考虑:以k=2为例,我们对于起始状态以及终止状态设定为00011,这样能使得不会出现第一个数以前以及最后一个数之后被占的情况。然后我们右移一位就能转移到下一个数去。转移的时候我们发现,如果被拿掉的这一位是0(没有被占),这是不可以的,因为除了它没有其他数字可以去占了,它必须拿掉这个0。也就是说,有0的时候我们是直接右移,不添加任何一个1。如果末尾不是0,那么一个1被吃掉,前面又要占掉一个位置(增加1个1),1的个数不变。所以始终是k个1。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long
     4 #define N 150
     5 #define mod 1000000007
     6 
     7 inline LL read(){
     8        LL x=0,f=1; char a=getchar();
     9        while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();}
    10        while(a>='0' && a<='9') x=x*10+a-'0',a=getchar();
    11        return x*f;
    12 }
    13 
    14 int n,K,cnt,id[2000],mark[N];
    15 
    16 struct matrix{
    17     int s[N][N];
    18     inline void reset(){memset(s,0,sizeof(s));}
    19 }w,dp;
    20 
    21 matrix operator * (matrix a,matrix b){
    22     matrix ret; ret.reset();
    23     for(int i=1;i<=cnt;i++)
    24         for(int j=1;j<=cnt;j++)
    25             for(int k=1;k<=cnt;k++)
    26                 ret.s[i][j]=((LL)ret.s[i][j]+1LL*a.s[i][k]*b.s[k][j])%mod;
    27     return ret;
    28 }
    29 
    30 void dfs(int x,int now,int num){
    31     if(x>2*K+1) {
    32         if(num==K) id[now]=++cnt,mark[cnt]=now;
    33         return;
    34     }
    35     dfs(x+1,(now<<1)|1,num+1);
    36     dfs(x+1,now<<1,num);
    37 }
    38 
    39 inline void prework(){
    40     cnt=0; memset(id,0,sizeof(id)); memset(mark,0,sizeof(mark));
    41     dfs(1,0,0);
    42     w.reset();
    43     for(int i=1;i<=cnt;i++){
    44         int x=mark[i];
    45         if(x&1){
    46             for(int k=0;k<2*K+1;k++) if(((1<<k)&x)==0) w.s[i][id[(x|(1<<k))>>1]]=1;
    47         }
    48         else w.s[i][id[x>>1]]=1;
    49     }
    50     dp.reset();
    51     dp.s[1][id[(1<<K)-1]]=1;
    52 }
    53 
    54 inline void fpow(int k){
    55     while(k){
    56         if(k&1) dp=dp*w;
    57         k>>=1; w=w*w;
    58     }
    59 }
    60 
    61 int main(){
    62     while(scanf("%d%d",&n,&K)!=EOF){
    63         if(!K) {puts("1");continue;}
    64         prework(); fpow(n);
    65         printf("%d
    ",dp.s[1][id[(1<<K)-1]]);
    66     }
    67     return 0;
    68 }

    T2:给定一棵树,每个节点的字符为它的度数。求解有多少个本质不同的子串满足结尾是开头的祖先(包括自己)。

    题解:其实就是众神眷顾的幻想乡,只不过字符集有点问题而已。

    以下这个代码如果不被卡还是跑得挺快的,当然极端数据可以卡到3000ms。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long
     4 #define N 500005
     5 
     6 inline LL read(){
     7        LL x=0,f=1; char a=getchar();
     8        while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();}
     9        while(a>='0' && a<='9') x=x*10+a-'0',a=getchar();
    10        return x*f;
    11 }
    12 
    13 namespace Suffix_Automation{
    14     int sroot=1,cnt=1;
    15     struct edges{
    16         int val,to;
    17         bool operator < (const edges& w)const{
    18             return val<w.val;
    19         }
    20     };
    21     struct sam{
    22         int par,len;
    23         set<edges>s;
    24     }a[2*N];
    25     inline int add(int last,int v){
    26         edges tr=(edges){v,0};
    27         if(a[last].s.count(tr)) return a[last].s.find(tr)->to;
    28         int p=last,now=++cnt; a[now].len=a[p].len+1;
    29         tr.to=now;
    30         while(p && !a[p].s.count(tr)) spj++,a[p].s.insert(tr),p=a[p].par;
    31         if(!p) a[now].par=sroot;
    32         else{
    33             int q=a[p].s.find(tr)->to;
    34             if(a[q].len==a[p].len+1) a[now].par=q;
    35             else{
    36                 int nq=++cnt;
    37                 a[nq]=a[q]; a[nq].len=a[p].len+1;
    38                 a[q].par=a[now].par=nq;
    39                 tr.to=nq;
    40                 while(p && a[p].s.count(tr) && a[p].s.find(tr)->to==q) 
    41                 a[p].s.erase(a[p].s.find(tr)),a[p].s.insert(tr),p=a[p].par;
    42             }
    43         }
    44         return now;
    45     }
    46 }
    47 
    48 #define SAM Suffix_Automation
    49 
    50 int n,head[N],cnt=1,d[N],final[N];
    51 
    52 struct edges{
    53     int to,next;
    54 }e[2*N];
    55 
    56 inline void insert(){
    57     int u=read(),v=read(); d[u]++; d[v]++;
    58     e[++cnt]=(edges){v,head[u]};head[u]=cnt;
    59     e[++cnt]=(edges){u,head[v]};head[v]=cnt;
    60 }
    61 
    62 void dfs(int x,int fa){
    63     final[x]=SAM::add(final[x],d[x]);
    64     if(!final[x]) return 0;
    65     for(int i=head[x];i;i=e[i].next){
    66         if(e[i].to==fa) continue;
    67         final[e[i].to]=final[x];
    68         dfs(e[i].to,x);
    69     }
    70 }
    71 
    72 int main(){
    73     n=read(); 
    74     for(int i=1;i<n;i++) insert();
    75     final[1]=1; dfs(1,0);
    76     LL ans=0;
    77     for(int i=1;i<=SAM::cnt;i++) ans+=SAM::a[i].len-SAM::a[SAM::a[i].par].len;
    78     printf("%lld
    ",ans);
    79     return 0;
    80 }

    T3:分块+bitset,不多说了(其实是没写代码。。

  • 相关阅读:
    Autofac的基本使用---4、使用Config配置
    Autofac的基本使用---3、泛型类型
    Autofac的基本使用---2、普通类型
    Autofac的基本使用---1、前言
    MVC中Autofac的使用
    EF快速入门--直接修改(简要介绍ObjectContext处理机制)
    EF生成模型时Disigner中无信息
    C语言关键字-volatile
    linux内核分析之内存管理
    (转)Linux SLUB 分配器详解
  • 原文地址:https://www.cnblogs.com/enigma-aw/p/6568030.html
Copyright © 2020-2023  润新知