LeetCode Weekly Contest 28
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的更多相关文章
- LeetCode Weekly Contest 8
LeetCode Weekly Contest 8 415. Add Strings User Accepted: 765 User Tried: 822 Total Accepted: 789 To ...
- leetcode weekly contest 43
leetcode weekly contest 43 leetcode649. Dota2 Senate leetcode649.Dota2 Senate 思路: 模拟规则round by round ...
- LeetCode Weekly Contest 23
LeetCode Weekly Contest 23 1. Reverse String II Given a string and an integer k, you need to reverse ...
- Leetcode Weekly Contest 86
Weekly Contest 86 A:840. 矩阵中的幻方 3 x 3 的幻方是一个填充有从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等. 给定一个 ...
- LeetCode Weekly Contest
链接:https://leetcode.com/contest/leetcode-weekly-contest-33/ A.Longest Harmonious Subsequence 思路:hash ...
- 【LeetCode Weekly Contest 26 Q4】Split Array with Equal Sum
[题目链接]:https://leetcode.com/contest/leetcode-weekly-contest-26/problems/split-array-with-equal-sum/ ...
- 【LeetCode Weekly Contest 26 Q3】Friend Circles
[题目链接]:https://leetcode.com/contest/leetcode-weekly-contest-26/problems/friend-circles/ [题意] 告诉你任意两个 ...
- 【LeetCode Weekly Contest 26 Q2】Longest Uncommon Subsequence II
[题目链接]:https://leetcode.com/contest/leetcode-weekly-contest-26/problems/longest-uncommon-subsequence ...
- 【LeetCode Weekly Contest 26 Q1】Longest Uncommon Subsequence I
[题目链接]:https://leetcode.com/contest/leetcode-weekly-contest-26/problems/longest-uncommon-subsequence ...
随机推荐
- CAD计算两曲线间最短路径(com接口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...
- chrome浏览器处理本地Ajax跨域
chrome浏览器下 项目开发过程中,用到了Ajax异步请求.若将项目放在本地服务器中,通过localhost访问文件,不会报错.若直接通过file://访问文件就会报错. 报错信息: XMLHttp ...
- java的四种引用,强弱软虚和jvm优化
1.强引用(StrongReference)强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.如下: Object o=new Object(); // 强引用 当内存 ...
- Python os模块和time模块 day4
一.os模块 print(os.listdir(r'/Users/smh/Desktop/整理'))#os.listdir() 列出某个目录下面的文件夹/文件 print(os.path.isfile ...
- uva-156(Ananagrams UVA - 156)
map容器的模板题,判断是否能交换字母顺序变成另外一个单词,只需要先把单词都变成小写字母.然后再按字母字典序排序,放入map中进行计数,然后把计数为一的再放入另一个容器,再排序输出即可 我的代码(刘汝 ...
- 使用MySQLMigrationToolkit快速将Oracle数据导入MySQL
使用MySQL Migration Toolkit快速将Oracle数据导入MySQL 上来先说点废话 本人最近在学习一些数据库方面的知识,之前接触过Oracle和MySQL,最近又很流行MongoD ...
- hdu 1273最大流
#include<stdio.h> #include<string.h> #define inf 1000000000 #include<queue> #defin ...
- Office 2003的卸载 与 Office 2013 的安装
一.Office 2003的卸载 软件:卸载Office2003.msi 运行该软件,等待几分钟即可, 二.Office 2013 的安装 1.Office Professional Plus 201 ...
- lead 函数和 lag函数
这两个函数的作用只能通过例子来解释,否则说不明白. 首先创建一个表 SQL> create table test (id number, name varchar2(8), val number ...
- WinCE:在Win7上连接WinCE手持设备
当我们通过usb将WinCE 手持设备与Win7 PC连接后,我们通常希望通过Windows Mobile Center软件与手持设备实现同步.方法很简单,从下列列表中选择适合自己操作系统的Windo ...