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. vue和iview中native点击事件修饰

    在父组件中给子组件绑定一个原生的事件,就将子组件变成了普通的HTML标签,不加'. native'事件是无法触 在vue中使用iview的dropdownMenu 上单纯的@click也不生效,要写成 ...

  2. 详解proxy_pass、upstream与resolver

    详解proxy_pass.upstream与resolver boldcautious 关注 2018.06.04 10:48 字数 1204 阅读 1434评论 0喜欢 2 应用场景 这里列举几个应 ...

  3. webpack-dev-middleware 与 webpack-hot-middlware

    dev-middleware:  live reload的实现: 思考一下我們要如何更新(live reload)呢? 當然是需要取得 webpack 編好的資料啊,於是就需要在從 request 到 ...

  4. 生成元(Digit Generator, ACM/ICPC Seoul 2005, UVa1583)

    如果x加上x的各个数字之和得到y,就说x是y的生成元.给出n(1≤n≤100000),求最小 生成元.无解输出0.例如,n=216,121,2005时的解分别为198,0,1979. [分析] 本题看 ...

  5. Linux之FTP/TFTP(vsftp、vsftpd) HTTP(httpd、apache) DHCP(dhcpd)

    FTP/TFTP(vsftp.vsftpd): FTP是File Transfer Protocol(文件传输协议)而中文简称为"文传协议".用于Internet上的控制文件的双向 ...

  6. Python - 模块(一)

    目录 Python - 模块(一) 模块的引用方式 常用模块 random(随机模块) os模块 sys 序列化模块 hashlib subprocess optparse struct Python ...

  7. JavaScript单元测试工具-Jest

    标注: 首先这并不是一篇完整的关于Jest的教程,只是个人在接触jest学习的一点随手笔记,大部分内容都是对官方文档的一些翻译. ----------------------------------- ...

  8. HDU 5442 Favorite Donut

    Favorite Donut Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

  9. nyoj 307

    /*这是一道最短路变形题 从每个有藏宝的地方为起点 求到各个点的可以的最大重量,相当于求出了从出口 到 一个藏宝点 所  允许的最大重量,把所有藏宝点的按重量 排序(从小到大)先到最小的藏宝点带上 宝 ...

  10. ESdata节点脱离集群,系统日志报120秒超时

    ES信息:Centos7.2,ES6.2.2 , MASTER:16核/128G物理 * 3 ,DATA:16核/128G/12块HDD6T组成RAID0 * 40, JVM开了30G,  目前只有一 ...