551. Student Attendance Record I + Student Attendance Record II
▶ 一个学生的考勤状况是一个字符串,其中各字符的含义是:A 缺勤,L 迟到,P 正常。如果一个学生考勤状况中 A 不超过一个,且没有连续两个 L(L 可以有多个,但是不能连续),则称该学生达标(原文表述:A student could be rewarded if his attendance record doesn't contain more than one 'A' (absent) or more than two continuous 'L' (late). )
▶ 551. 给定一个学生的考勤状况,判断他能否达标。
● 代码,4 ms,简单的计数,最快的解法算法与之相同
class Solution
{
public:
bool checkRecord(string s)
{
int i, a, l;
for (i = a = l = ; i < s.size(); i++)
{
if (s[i] == 'A')
a++;
if (s[i] == 'L')
l++;
else // 出现 A 或 P 时均要清空 L 计数
l = ;
if (a >= || l > )
return false;
}
return true;
}
};
▶ 552. 给定正整数 n,考虑所有长度为 n 的考勤状况(3n 种可能),计算达标的考勤状况数,该数字可能非常大,取关于 109 + 7(竟然是个素数)模作为输出结果
● 自己的代码,29 ms,时间复杂度 O(n),考虑递推数列,一个达标序列只能是以下三种情况:
a[ k ] 表长度为 k,以 P 结尾,不含 A 的达标序列个数
b[ k ] 表长度为 k,以 PL 结尾,不含 A 的达标序列个数(不能是 LLLP 结尾)
c[ k ] 表长度为 k,以 LL 结尾,不含 A 的达标序列个数(不能是 LLL 结尾)
注意到 a[ 1 ] = b[ 1 ] = 1,c[ 1 ] = 0,a[ k ] = a[ k - 1 ] + b[ k - 1 ] + c[ k - 1](任意一种达标序列添个 P),b[ k ] = a[ k - 1 ](P 结尾的达标序列添个 L),c[ k ] = b[ k - 1 ](PL 结尾的达标序列添个 L)
约化后就变成了 a[ 1 ] = 1,a[ 2 ] = 2,a[ 3 ] = 4,a[ n ] = a[ n - 1 ] + a[ n - 2 ] + a[ n - 3 ] ( n ≥ 4 )
对上述数列打表,使用长度为 n+1 的表 f,其中 a[ k ] = f[ k - 1 ],即所有下标有一单位的平移,在代码中注意控制
因为打表序列中 A 至多一个,所以按照 A 的位置分类讨论:
① 不含A,一共有 a[ n ] + b[ n ] + c[ n ] = a[ n + 1 ] 种情况,等于 f[ n ](打表要长一格的原因)
② A 在开头,一共有 a[ n - 1 ] + b[ n - 1 ] + c[ n - 1 ] = a[ n ] 种情况,等于 f[ n - 1 ]
③ A 在结尾,同上,等于 f[ n - 1 ]
④ A 在中间,考虑 A 的左边有长度为 i 的不含 A 的序列,且 A 的右边有长度为 n - i - 1 的不含A的序列,一共是 ( a[ i ] + b[ i ] + c[ i ] ) * ( a[ n - i - 1 ] + b[ n - i - 1 ] + c[ n - i - 1 ] ),即 f[ i ] * f[ n - i - 1 ],
i 在 i = 1 到 i = n - 2 之间求和。
注意每一步取模运算,因为 f 本身是指数级增长的。
class Solution
{
public:
int checkRecord(int n)
{
if (n == )
return ;
const int m = ;
vector<long long> f(n + , );
int i,sum;
for (f[] = , f[] = , f[] = , i = ; i <= n; f[i] = (f[i - ] + f[i - ] + f[i - ]) % m, i++);
for (sum = (f[n] + f[n - ] * ) % m, i = ; i < n - ; i++)
sum = (sum + f[i] * f[n - i - ]) % m;
return sum;
}
};
● 代码,4 ms,使用一个矩阵的幂来计算递推
#define ENTRY(A, i, j) ((A)[(i) * n + (j)]) int64_t* NewMatrix(size_t n)
{
assert(n >= );
int64_t* temp = (int64_t*)calloc(n * n, sizeof(int64_t));
assert(temp != NULL);
return temp;
} void FreeMatrix(int64_t* A)
{
free(A);
} void SetMatrix(int64_t* A, int64_t* B, size_t n)
{
memcpy(A, B, n * n * sizeof(int64_t));
} void IdentityMatrix(int64_t* A, size_t n)// 将方阵 A 赋值为单位方阵
{
int i, j;
for (i = ; i < n; i++)
{
for (j = ; j < n; j++)
ENTRY(A, i, j) = (i == j);
}
} void MatrixMultiply(int64_t* A, int64_t* B, size_t n)// 方阵乘法 A = A * B
{
assert(n >= );
int64_t* C = NewMatrix(n);
int i, j, k;
for (i = ; i < n; ++i)
{
for (j = ; j < n; ++j)
{
ENTRY(C, i, j) = ;
for (k = ; k < n; ++k)
ENTRY(C, i, j) += ENTRY(A, i, k) * ENTRY(B, k, j);
}
}
memcpy(A, C, n * n * sizeof(int64_t));
FreeMatrix(C);
} void MatrixPower(int64_t* C, int64_t* A, size_t n, int m)// 方阵幂 C = A ^ m
{
assert(n >= );
assert(m >= );
int64_t* B = NewMatrix(n);
SetMatrix(B, A, n);
IdentityMatrix(C, n);
for (; m > ; m /= )// 二进制方法
{
if (m % == )
MatrixMultiply(C, B, n);
MatrixMultiply(B, B, n);
}
FreeMatrix(B);
} void MatrixModulus(int64_t* A, size_t n, int64_t modulus)// 方阵逐格求模 A %= m
{
int i, j;
for (i = ; i < n; ++i)
{
for (j = ; j < n; ++j)
ENTRY(A, i, j) = ENTRY(A, i, j) % modulus;
}
} void MatrixModulusPower(int64_t* C, int64_t* A, size_t n, int m, int64_t modulus)// C = A ^ m % modulus
{
assert(n >= );
assert(m >= );
int64_t* B = NewMatrix(n);
SetMatrix(B, A, n);
IdentityMatrix(C, n);
for (; m > ;m/=)
{
if (m % == )
{
MatrixMultiply(C, B, n);
MatrixModulus(C, n, modulus);
}
MatrixMultiply(B, B, n);
MatrixModulus(B, n, modulus);
}
FreeMatrix(B);
} int AttendanceNumber(int m)
{
assert(m >= );
size_t n = ;
int64_t initial_vector[] = { , , , , , };
int64_t modulus = ;
int64_t* A = NewMatrix(n);
ENTRY(A, , ) = ;
ENTRY(A, , ) = ;
ENTRY(A, , ) = ;
ENTRY(A, , ) = ;
ENTRY(A, , ) = ;
ENTRY(A, , ) = -;
ENTRY(A, , ) = -;
ENTRY(A, , ) = -;
ENTRY(A, , ) = ;
ENTRY(A, , ) = ;
ENTRY(A, , ) = ;
int64_t answer = ;
if (m <= )
answer = initial_vector[m];
else
{
int64_t* C = NewMatrix(n);
MatrixModulusPower(C, A, n, m - n + , modulus);
for (size_t i = ; i < n; ++i)
answer += ENTRY(C, n - , i) * initial_vector[i];
answer = (answer % modulus + modulus) % modulus;
FreeMatrix(C);
}
FreeMatrix(A);
return answer;
} #undef ENTRY class Solution
{
public:
int checkRecord(int n)
{
return AttendanceNumber(n);
}
};
● 初版动态规划(MLE),f[ i ][ j ][ k ] 表示长度为 i,至多 j 个 A,至多 k 个连续 L 的序列。所求目标为 f[ n ][ 1 ][ 2 ],转移方程如下,发现可以用矩阵幂来一次性计算 f[ n ]

class Solution
{
public:
int checkRecord(int n)
{
const int MOD = ;
vector<vector<vector<int>>> f(n + , vector<vector<int>>(, vector<int>(3, 0)));
int i, j, k, val;
for (i = ; i < ; i++)
for (j = ; j < ; f[][i][j++] = );
for (i = ; i <= n; i++)
{
for (j = ; j < ; j++)
{
for (k = ; k < ; k++)
{
val = f[i - ][j][]; // P
if (j > ) // A
val = (val + f[i - ][j - ][]) % MOD;
if (k > ) // L
val = (val + f[i - ][j][k - ]) % MOD;
f[i][j][k] = val;
}
}
}
return f[n][][];
}
};
● 改进动态规划,8 ms,直接用矩阵幂来计算
class Solution
{
public:
const int MOD = , M = ;
void mul(vector<vector<int>>& A, vector<vector<int>>& B)
{
vector<vector<int>> temp(M, vector<int>(M, ));
int i, j, k;
for (i = ; i < M; i++)
{
for (j = ; j < M; j++)
{
for (k = ; k < M; k++)
temp[i][j] = (int)((temp[i][j] + (long)A[i][k] * B[k][j]) % MOD);
}
}
A = temp;
return;
}
void pow(vector<vector<int>>& A, int n)
{
vector<vector<int>> temp(M, vector<int>(M, ));
for (int i = ; i < M; temp[i][i] = , i++);
for (; n > ; n /= )
{
if (n % )
mul(temp, A);
mul(A, A);
}
A = temp;
return;
}
int checkRecord(int n)
{
vector<vector<int>> A = \
{
{ , , , , , },
{ , , , , , },
{ , , , , , },
{ , , , , , },
{ , , , , , },
{ , , , , , },
};
pow(A, n + );
return A[][];
}
};
● 代码,深度优先遍历,TLE,说明穷举肯定不行
class Solution
{
public:
int checkRecord(int n)
{
long long res = ;
dfs(n, , , , res);
return res % ;
}
void dfs(int n, int s, int A, int L, long long& res)// 当前共 s 位,有 A 个 A 和 L 个 L
{
if (s == n)
{
res++;
return;
}
dfs(n, s + , A, , res); //add "P"
if (A < )
dfs(n, s + , A + , , res);
if (L <= )
dfs(n, s + , A, L + , res);
}
};
551. Student Attendance Record I + Student Attendance Record II的更多相关文章
- 1 实现添加功能 1.1 定义一个学员类(Student),在Student类中定义姓名、性别和年龄属性,定义有 参数的构造方法来初始化所以的成员属性 1.2 创建学员类对象来存放学员信息,并且为每一个学生对象添加的相应的编号。并将 学员类对象添加到Map<Integer,Student>集合中 1.3 添加完成后,显示所有已添加的学员姓名 1.4 限制年龄文本框只能输入正整数,否则的会采
学生类 package com.lanxi.demo1_3; public class Student { private String name; private String sex; priva ...
- 构建一个学生Student,根据类Student的定义,创建五个该类的对象,输出每个学生的信息,计算并输出这五个学生Java语言成绩的平均值,以及计算并输出他们Java语言成绩的最大值和最小值。
定义一个表示学生信息的类Student,要求如下: (1)类Student的成员变量: sNO 表示学号: sName表示姓名: sSex表示性别: sAge表示年龄: sJava:表示Java课程成 ...
- GitHub Student Developer Pack创建个人网站
链接:https://zhuanlan.zhihu.com/p/20531579 这个开发包里有什么?作为学生开发者,如何最大化利用它的价值? Atom编辑器,GitHub推出的编辑器,和Sublim ...
- C# 9.0新特性详解系列之五:记录(record)和with表达式
1 背景与动机 传统面向对象编程的核心思想是一个对象有着唯一标识,表现为对象引用,封装着随时可变的属性状态,如果你改变了一个属性的状态,这个对象还是原来那个对象,就是对象引用没有因为状态的改变而改变, ...
- C#中的记录(record)
从C#9.0开始,我们有了一个有趣的语法糖:记录(record) 为什么提供记录? 开发过程中,我们往往会创建一些简单的实体,它们仅仅拥有一些简单的属性,可能还有几个简单的方法,比如DTO等等,但是这 ...
- Method and apparatus for encoding data to be self-describing by storing tag records describing said data terminated by a self-referential record
A computer-implemented method and apparatus in a computer system of processing data generated by a f ...
- salesforce 零基础学习(六十二)获取sObject中类型为Picklist的field values(含record type)
本篇引用以下三个链接: http://www.tgerm.com/2012/01/recordtype-specific-picklist-values.html?m=1 https://github ...
- SQL Server 堆表行存储大小(Record Size)
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 堆表行记录存储格式(Heap) 案例分析(Case) 参考文献(References) 二.背 ...
- Student管理系统
使用三层架构实现Student管理系统,分为Studrnt.Model层,Student.DAL层,Student.BLL层和Student.UI层 步骤分析: 1.在Student.Model添加S ...
随机推荐
- 这些HTML、CSS知识点,面试和平时开发都需要 No5-No7(知识点:文字设置、设置背景、数据列表)
系列知识点汇总 这些HTML.CSS知识点,面试和平时开发都需要 No1-No4(知识点:HTML.CSS.盒子模型.内容布局) 这些HTML.CSS知识点,面试和平时开发都需要 No5-No7(知识 ...
- ContentNegotiatingViewResolver多种输出格式实例: json/jsp/xml/xls/pdf
ContentNegotiatingViewResolver多种输出格式实例: json/jsp/xml/xls/pdf 本例用的是javaConfig配置 以pizza为例. json输出需要用到的 ...
- bzoj1044: [HAOI2008]木棍分割 二分+dp
有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少 ...
- uva-1636-概率
https://vjudge.net/problem/UVA-1636 给出一个左轮手枪的弹夹串,第一枪是空的,问是继续打还是转一转再打下一枪还为空的概率大.继续打为空的概率就是 '00'的个数比上' ...
- UVALive-3126 Taxi Cab Scheme (DAG的最小路径覆盖)
题目大意:要给n个人安排车,已知每个人的出发时间和起点与终点,问最少需要安排几辆车才能完成任务. 题目分析:最小路径覆盖.如果送完a到目的地后能在b出发之前赶来接b,那么连一条有向边a->b,最 ...
- Java 调用 PHP 实例(五)
java代码: package test; import java.io.BufferedReader; import java.io.File; import java.io.IOException ...
- PHP:第五章——字符串输出函数
<?php header("Content-Type:text/html;charset=utf-8"); /*字符串输出函数*/ //1.echo 输出一个或多个字符 // ...
- 转载:【Oracle 集群】RAC知识图文详细教程(八)--Oracle 11G RAC数据库安装
文章导航 集群概念介绍(一) ORACLE集群概念和原理(二) RAC 工作原理和相关组件(三) 缓存融合技术(四) RAC 特殊问题和实战经验(五) ORACLE 11 G版本2 RAC在LINUX ...
- 纪念又一次ak
t1网络流 随便建个图就可以了 t2单调队列 分成两组来做 t3dp+高精度 为了不被卡厂用了万进制
- [转] .net软件反编译笔记
原文地址:http://blog.csdn.net/three_bird/article/details/51433734 在软件的破解及源码获取及重新编译的道路上会遇到一些问题,书此备查. 大名鼎鼎 ...