1. 551. Student Attendance Record I

2. 552. Student Attendance Record II

hihocode原题,https://hihocoder.com/contest/offers10/problems

直接粘贴代码。

其实这个第二题的问题挺多的,这里还是写一下分析过程。

我刚开始做的时候,考虑也是计数dp,一维记录a的个数,一维记录末尾l的个数,然后考虑转移,后来好像是因为转移情况复杂,简化为不考虑a的个数,因为a的个数只有1个,所以可以单独考虑,然后考虑只有p和l的情况,这样的问题应该是很好考虑的,我写的有点

复杂,我是记录末尾是什么,其实只用考虑末尾l的个数就行,只用一维就可以解决,而我使用了2维,枚举最后的2个字符是什么,还是比较繁琐的。计算过程,就是状态的转移过程,很好理解。

接下来考虑a的情况,最后的结果肯定先要加上没有a的情况,然后枚举a的位置,然后左右2边就又变成上面没a的情况,把左和右乘起来,就是最后的结果。

我的做法不具有通用性,而且绕的弯子有点大,没有抓住问题的本质。

接下来考虑正常的做法,计数dp,一维记录a的个数,一维记录末尾l的个数,然后考虑转移的情况。

转移的详细分析:http://bookshadow.com/weblog/2017/04/16/leetcode-student-attendance-record-ii/

其实自己手动分析,其实也是很简单的。

注意:上面的考虑的是,谁可以转移到我,这是一个收集的过程,分析可能的情况,而且情况数目很多,代码量大,很容易出错

解法二:

 #include<bits/stdc++.h>
#define pb push_back
typedef long long ll;
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e5 + ;
const int mod = 1e9 + ;
ll dp[maxn][][];
int n;
void add(ll& x, ll y) {
x = (x + y) % mod;
}
void solve() {
cin >> n;
dp[][][] = ;
for (int i = ; i <= n; i++) {
add(dp[i][][], dp[i - ][][]);
add(dp[i][][], dp[i - ][][]);
add(dp[i][][], dp[i - ][][]); add(dp[i][][], dp[i - ][][]);
add(dp[i][][], dp[i - ][][]); add(dp[i][][], dp[i - ][][]);
add(dp[i][][], dp[i - ][][]); add(dp[i][][], dp[i - ][][]);
add(dp[i][][], dp[i - ][][]);
add(dp[i][][], dp[i - ][][]);
add(dp[i][][], dp[i - ][][]);
add(dp[i][][], dp[i - ][][]);
add(dp[i][][], dp[i - ][][]); }
ll res = ;
for (int i = ; i < ; i++)
for (int j = ; j < ; j++)
add(res, dp[n][i][j]);
cout << res << endl;
} int main() {
freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
ios::sync_with_stdio();
cin.tie(); cout.tie();
solve();
return ;
}

转移复杂,需要考虑的情况多。

然后我参考排行榜第一名的代码,就有下面的分析:

所以就有下面的分析:其实应该考虑的是:我可以转移到谁,这是一个分发的过程,因为当前字符可能为a,p, l,所以是很好考虑的,代码也相对好写些

解法三:

 #include<bits/stdc++.h>
#define pb push_back
typedef long long ll;
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e5 + ;
const int mod = 1e9 + ;
ll dp[maxn][][];
int n;
void add(ll& x, ll y) {
x = (x + y) % mod;
}
void solve() {
cin >> n;
dp[][][] = ;
for (int i = ; i < n; i++) {
for (int x = ; x < ; x++) {
for (int y = ; y < ; y++) {
ll cur = dp[i][x][y];
if(cur == ) continue;
add(dp[i + ][x][], cur);
if(x + < ) {
add(dp[i + ][x + ][], cur);
}
if(y + < )
add(dp[i + ][x][y + ], cur);
}
}
}
ll res = ;
for (int i = ; i < ; i++)
for (int j = ; j < ; j++)
add(res, dp[n][i][j]);
cout << res << endl;
} int main() {
freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
ios::sync_with_stdio();
cin.tie(); cout.tie();
solve();
return ;
}

上面的代码都可以采用滚动数组优化。

其实分析到这里就差不多了,更详细的做法是贴出代码,一步一步解释,但是那样实在是太麻烦了,许多事情还是需要自己去走一遍的。

上面算是3种方法,第三种是最好的。

这个题目的n的限制为1e5,其实如果为1e8, 可以做么,其实是可以的,搞出来一个转移矩阵,然后快速幂来解决的,这也算是通用的套路吧。

转移矩阵的写法:

 #include<bits/stdc++.h>
#define pb push_back
typedef long long ll;
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e3 + ;
const int mod = 1e9 + ;
struct mat {
ll a[][];
mat() {
memset(a, , sizeof a);
}
void pr() {
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++)
cout << a[i][j] << " ";
cout << endl;
}
}
};
mat mul(mat& a, mat& b) {
mat c;
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
for (int k = ; k < ; k++) {
c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j] % mod) % mod;
}
}
}
return c;
}
mat tr, one;
int f(int x, int y) {
return x * + y;
}
void init() {
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
int cur = f(i, j);
one.a[cur][cur] = ;
tr.a[cur][f(i, )] = ;
if(i + < )
tr.a[cur][f(i + , )] = ;
if(j + < )
tr.a[cur][f(i, j + )] = ;
}
} }
int n;
void solve() {
cin >> n;
init();
//tr.pr();
//one.pr();
mat res;
res.a[][] = ;
while(n) {
if(n & ) one = mul(one, tr);
n >>= ;
tr = mul(tr, tr);
}
res = mul(res, one);
ll r = ;
for (int i = ; i < ; i++)
r = (r + res.a[][i]) % mod;
cout << r << endl;
} int main() {
freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
ios::sync_with_stdio();
cin.tie(); cout.tie();
solve();
return ;
}

相关的题目:

https://hihocoder.com/contest/offers13/problem/4  需要搞出状态转移方程,然后快速幂解决。

https://codejam.withgoogle.com/codejam/contest/10214486/dashboard#s=p3 这个难度比较高,也是转移方程的构造。

就这样吧,写了这么多啰嗦的话,本来只是想贴一下自己写的。

同时也暴露出一个问题,题目不是自己ac就完了,需要看一下别人是怎么做的,怎么想的,有没有什么巧妙的思路,这个过程才是关键的,这样才能提高和进步。

 class Solution {
public:
bool checkRecord(string s) {
int n = s.size();
int a = ;
for (int i = ; i < n; i++) {
if(s[i] == 'A') {
a++;
if(a > ) return ;
}
if(s[i] == 'L') {
if(i + < n && s[i + ] == 'L' && s[i + ] == 'L')
return ;
}
}
return ;
}
};
 typedef long long ll;
const int maxn = 1e5 + ;
const int mod = 1e9 + ;
ll dp[maxn][][];
ll s[maxn];
class Solution {
public:
int checkRecord(int n) {
if(n == ) {
//cout << 3 << endl;
return ;
}
if(n == ) {
//cout << 8 << endl;
return ;
}
// O L A
// 0 1 2
memset(s, , sizeof s);
memset(dp, , sizeof dp);
for (int i = ; i < ; i++)
for (int j = ; j < ; j++)
dp[][i][j] = ;
for (int c = ; c <= n; c++) {
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
for (int x = ; x < ; x++) {
if(i == && j == && x == ) {
continue;
}
dp[c][j][x] = (dp[c][j][x] + dp[c - ][i][j]) % mod;
}
}
}
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
s[c] = (s[c] + dp[c][i][j]) % mod;
}
}
}
ll res = ;
res = s[n];
s[] = ;
s[] = ;
s[] = ;
for (int i = ; i <= n; i++) {
int left = i - , right = n - i;
res = (res + s[left] * s[right] % mod) % mod;
}
return res; }
};

3. 553. Optimal Division

刚开始,看到长度为10,以为是暴力枚举,因为枚举每一个位置的优先级,然后计算,但是仔细想想,要是实现起来还是比较麻烦的。考虑到是第二题,不会这么麻烦,考虑

数学的分析方法,结果最大,除数最小,什么时候最小,当然是连除,越除越小,然后答案就很明显了。直接输出结果。

 class Solution {
public:
string optimalDivision(vector<int>& nums) {
int n = nums.size();
stringstream ss;
if(n == ) {
ss << nums[];
} else if(n == ) {
ss << nums[] << "/" << nums[];
} else {
ss << nums[] << "/(" << nums[];
for (int i = ; i < n; i++)
ss << "/" << nums[i];
ss << ")";
}
return ss.str();
}
};

4. 555. Split Concatenated Strings

说实话,看完真的一点想法也没有,完全懵逼。

静下心来分析,考虑整个字符串长度为1000,那么可以简单的枚举每一个字符串的开始,每一个字符都有可能作为开头,接下来考虑,固定头部的时候,其他的字符串怎么办,其实是很明显的,因为其他字符串只有顺序和逆序2种情况,而且要使得结果最大,肯定选择2种里面较大的那一种,显然是确定的,所以枚举的每一个起始字符以后,可以在O(n)的复杂度内,计算出这个串,然后不断的更新结果,就可以了。

 class Solution {
public:
string splitLoopedString(vector<string>& v) {
int n = v.size();
if(n == ) return "";
string res;
for (string&t : v) {
string td = t;
reverse(td.begin(), td.end());
if(td > t)
t = td;
res += t;
}
//cout << res << endl;
for (int i = ; i < n; i++) {
int sz = v[i].size();
for (int j = ; j < sz; j++) {
string ml = v[i].substr(j, sz - j), mr = v[i].substr(, j);
string rl = v[i].substr(j + , sz - j - ), rr = v[i].substr(, j + );
reverse(rl.begin(), rl.end());
reverse(rr.begin(), rr.end());
// ml mr
// rr rl
for (int j = (i + ) % n; j != i; j = (j + ) % n) {
ml += v[j];
rr += v[j];
} ml += mr;
rr += rl;
//cout << ml << endl;
//cout << rr << endl;
res = max(res, max(ml, rr));
}
}
return res;
}
};

LeetCode Weekly Contest 28的更多相关文章

  1. LeetCode Weekly Contest 8

    LeetCode Weekly Contest 8 415. Add Strings User Accepted: 765 User Tried: 822 Total Accepted: 789 To ...

  2. leetcode weekly contest 43

    leetcode weekly contest 43 leetcode649. Dota2 Senate leetcode649.Dota2 Senate 思路: 模拟规则round by round ...

  3. LeetCode Weekly Contest 23

    LeetCode Weekly Contest 23 1. Reverse String II Given a string and an integer k, you need to reverse ...

  4. Leetcode Weekly Contest 86

    Weekly Contest 86 A:840. 矩阵中的幻方 3 x 3 的幻方是一个填充有从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等. 给定一个 ...

  5. LeetCode Weekly Contest

    链接:https://leetcode.com/contest/leetcode-weekly-contest-33/ A.Longest Harmonious Subsequence 思路:hash ...

  6. 【LeetCode Weekly Contest 26 Q4】Split Array with Equal Sum

    [题目链接]:https://leetcode.com/contest/leetcode-weekly-contest-26/problems/split-array-with-equal-sum/ ...

  7. 【LeetCode Weekly Contest 26 Q3】Friend Circles

    [题目链接]:https://leetcode.com/contest/leetcode-weekly-contest-26/problems/friend-circles/ [题意] 告诉你任意两个 ...

  8. 【LeetCode Weekly Contest 26 Q2】Longest Uncommon Subsequence II

    [题目链接]:https://leetcode.com/contest/leetcode-weekly-contest-26/problems/longest-uncommon-subsequence ...

  9. 【LeetCode Weekly Contest 26 Q1】Longest Uncommon Subsequence I

    [题目链接]:https://leetcode.com/contest/leetcode-weekly-contest-26/problems/longest-uncommon-subsequence ...

随机推荐

  1. git 缓存密码导致的不能和远程仓库交互unable to access... 403错误

    尝试了各种方式,包括卸载等最终解决方案: 查看本机的credential 是否已经被清空. 如果输入了 git config credential.helper 命令之后没有输出,说明 git 的配置 ...

  2. LDAP个人理解

    在新的公司办公,所有的后台系统或文档系统都公用一个LDAP账号. 接触到这个新名词,就查了一下,谈谈个人理解: LDAP是个协议, 简单地说,可以把LDAP服务理解为一套存放你账户密码的数据库系统.市 ...

  3. 数据结构与算法(5) -- deque

    vector是单向开口的连续线性空间,deque则是一种双向开口的连续线性空间.所谓双向开口,意思是可以在头尾两端分别做元素的插入和删除操作.stl中deque与vector最大的差异,一在于dequ ...

  4. uva-156(Ananagrams UVA - 156)

    map容器的模板题,判断是否能交换字母顺序变成另外一个单词,只需要先把单词都变成小写字母.然后再按字母字典序排序,放入map中进行计数,然后把计数为一的再放入另一个容器,再排序输出即可 我的代码(刘汝 ...

  5. uva 1586 Molar mass(Uva-1586)

    这题做的相当的复杂...之前做的现在应该能简单一点了写的. 我的代码: #include <bits/stdc++.h> using namespace std; main() { int ...

  6. Tomcat启动失败--Several ports (8005, 8080, 8009)

    启动Tomcat服务器报错: Several ports (8005, 8080, 8009) required by Tomcat v7.0 Server at localhost are alre ...

  7. JavaScript学习笔记之DOM介绍

    目录 1.简介 2.方法 3.属性 4.访问节点 5.修改节点 6.添加节点 7.删除节点 8.替换节点 9.改变 CSS 1.简介 文档对象模型(Document Object Model,DOM) ...

  8. c# SQL事务

    SQL事务执行 SqlTransaction   sqlTransaction   =   sqlConnection.BeginTransaction();    SqlCommand   sqlC ...

  9. BUPT2017 wintertraining(16) #9

    龟速补题.目前基本弃坑.已暂时放弃 D.I 两题. 下面不再写题意了直接说解法注意事项之类,直接放contest链接. https://vjudge.net/contest/151537 A.The ...

  10. 手工MAVEN建立WEBAPP项目并打包部署

    参考URL: http://my.oschina.net/zimingforever/blog/266028 最简单的东东,可以就两条命令: 建立目录及POM.XML: mvn archetype:g ...