Educational Codeforces Round 40 F. Runner's Problem
Educational Codeforces Round 40 F. Runner's Problem
题意:
给一个$ 3 * m \(的矩阵,问从\)(2,1)$ 出发 走到 \((2,m)\) 的方案数 \(mod 1e9 + 7\), 走的规则和限制如下:
From the cell (i, j) you may advance to:
- (i - 1, j + 1) — only if i > 1,
- (i, j + 1), or
- (i + 1, j + 1) — only if i < 3.
给出了$n $个限制 每个限制如下描述
\(a_i, l_i, r_i l_i <= r_i 1<=a_i <= 3\) 表示第\((a_i, l_i)\) 到 \((a_i, ri)\) 都是不可走的
\(n <= 10000 , m <= 10^{18}\)
思路:
考察没有限制的情况, 写出转移矩阵做快速幂即可
\(\begin{bmatrix} 1& 1 &0 \\ 1& 1 &1 \\ 0& 1 &1 \end{bmatrix}\)
那么给定了限制之后,其实就是转移矩阵在某一段内不会发生变化,处理出每一段做快速幂即可。
最开始我处理每一段的方法有点傻逼,将所有的端点按左开右闭的方式排序,然后对于取出的每一段区间判断第1,2,3行在这段区间内是否有障碍,我采用了对每一行的障碍排序,再用指针的方式来判断是否有障碍。
#include<bits/stdc++.h>
#define LL long long
#define P pair<int,int>
using namespace std;
const int mod = 1e9 + 7;
vector<pair<LL,LL> > a[3];
vector<pair<LL,int> >p;
int n, x;
LL m, l, r;
struct MAT{
int a[3][3];
MAT operator*(const MAT &rhs){
MAT ans;
memset(ans.a, 0, sizeof(ans.a));
for(int i = 0;i < 3;i++){
for(int j = 0;j < 3;j++){
for(int k = 0;k < 3;k++){
ans.a[i][j] = (ans.a[i][j] + 1LL * a[i][k] * rhs.a[k][j] % mod) % mod;
}
}
}
return ans;
}
MAT operator^(LL k){
MAT ans, A = *this;
for(int i = 0;i < 3;i++){
for(int j = 0;j < 3;j++) ans.a[i][j] = (i == j?1:0);
}
for(;k;k >>= 1,A = A * A) if(k & 1) ans = ans * A;
return ans;
}
}mat;
int b[3][3];
void init(){
b[0][0] = b[0][1] = 1;
b[1][0] = b[1][1] = b[1][2] = 1;
b[2][1] = b[2][2] = 1;
b[0][2] = b[2][0] = 0;
}
void gao(int row){
for(int i = 0;i < 3;i++) mat.a[row][i] = 0;
}
int main()
{
init();
cin>>n>>m;
for(int i = 0;i < n;i++){
scanf("%d%lld%lld",&x,&l,&r);
a[x - 1].push_back(make_pair(l,r));
p.push_back(make_pair(l - 1, 0));
p.push_back(make_pair(r, 1));
}
p.push_back(make_pair(1,0));
p.push_back(make_pair(m, 1));
sort(p.begin(),p.end());
p.erase(unique(p.begin(),p.end()),p.end());
for(int i = 0;i < 3;i++) sort(a[i].begin(),a[i].end());
LL mxr[3] = {1,1,1};
LL ans[3] = {0,1,0};
int now[3] = {0};
l = p[0].first;
for(int i = 1; i < p.size();i++){
r = p[i].first;
memcpy(mat.a, b, sizeof(b));
for(int j = 0;j < 3;j++){
int &xx = now[j];
while(xx < a[j].size() && a[j][xx].first <= l + 1 &&
(mxr[j] = max(a[j][xx].second,mxr[j])) < r) xx++;
if(xx < a[j].size() && a[j][xx].first <= l + 1 && mxr[j] >= r){
gao(j);
}
}
mat = mat ^ (r - l);
LL tmp[3] = {0};
for(int j = 0;j < 3;j++){
for(int k = 0;k < 3;k++) {
tmp[j] += 1LL * mat.a[j][k] * ans[k] % mod;
tmp[j] %= mod;
}
memcpy(ans, tmp, sizeof(tmp));
l = p[i].first;
}
cout<<ans[1]<<endl;
return 0;
}
实际上存端点的时候 可以把该端点是起点还是终点以及在哪一行存进去,这样就可以单独每一行进行维护。
当某一行遇到一个起点后,意味着该行从这个点开始都是有障碍的,直到遇到一个终点+1 后面才没有障碍,
这样就容易判断的多。
常用的区间标记操作,只是这里一时没有将这个知识用上来,以致于采用前面的做法觉得复杂很多。
#include<bits/stdc++.h>
#define LL long long
#define P pair<int,int>
using namespace std;
const int mod = 1e9 + 7;
int n, x;
LL m, l, r;
struct MAT{
int a[3][3];
MAT operator*(const MAT &rhs){
MAT ans;
memset(ans.a, 0, sizeof(ans.a));
for(int i = 0;i < 3;i++){
for(int j = 0;j < 3;j++){
for(int k = 0;k < 3;k++){
ans.a[i][j] = (ans.a[i][j] + 1LL * a[i][k] * rhs.a[k][j] % mod) % mod;
}
}
}
return ans;
}
MAT operator^(LL k){
MAT ans, A = *this;
for(int i = 0;i < 3;i++){
for(int j = 0;j < 3;j++) ans.a[i][j] = (i == j?1:0);
}
for(;k;k >>= 1,A = A * A) if(k & 1) ans = ans * A;
return ans;
}
};
struct node{
LL x;
int row, f;
node(LL x,int row,int f):x(x),row(row),f(f){};
bool operator<(const node&rhs)const{
return x < rhs.x;
}
};
vector<node> p;
int main()
{
cin>>n>>m;
for(int i = 0;i < n;i++){
scanf("%d%lld%lld",&x,&l,&r);
p.push_back(node(l, x - 1, 1));
p.push_back(node(r + 1, x - 1, -1));
}
p.push_back(node(m + 1, 1, -1));
sort(p.begin(),p.end());
int isobstacle[4] = {0};
MAT ans;
for(int i = 0;i < 3;i++) for(int j = 0;j < 3;j++) ans.a[i][j] = (i == j?1:0);
l = 1;
for(int i = 0; i < p.size();i++){
r = p[i].x;
LL d = r - l - 1; /// 区间左闭右开
if(d){
MAT mat;
for(int i = 0;i < 3;i++){ // 初始化转移矩阵
for(int j = 0;j < 3;j++) {
if(!isobstacle[i] && abs(i - j) <= 1) mat.a[i][j] = 1;
else mat.a[i][j] = 0;
}
}
ans = (mat ^ d) * ans;
}
isobstacle[p[i].row] += p[i].f;
l = r - 1;
}
cout<<ans.a[1][1]<<endl;
return 0;
}
Educational Codeforces Round 40 F. Runner's Problem的更多相关文章
- Educational Codeforces Round 40千名记
人生第二场codeforces.然而遇上了Education场这种东西 Educational Codeforces Round 40 下午先在家里睡了波觉,起来离开场还有10分钟. 但是突然想起来还 ...
- Educational Codeforces Round 40 C. Matrix Walk( 思维)
Educational Codeforces Round 40 (Rated for Div. 2) C. Matrix Walk time limit per test 1 second memor ...
- Educational Codeforces Round 40 (Rated for Div. 2) Solution
从这里开始 小结 题目列表 Problem A Diagonal Walking Problem B String Typing Problem C Matrix Walk Problem D Fig ...
- Educational Codeforces Round 40 I. Yet Another String Matching Problem
http://codeforces.com/contest/954/problem/I 给你两个串s,p,求上一个串的长度为|p|的所有子串和p的差距是多少,两个串的差距就是每次把一个字符变成另一个字 ...
- Educational Codeforces Round 61 F 思维 + 区间dp
https://codeforces.com/contest/1132/problem/F 思维 + 区间dp 题意 给一个长度为n的字符串(<=500),每次选择消去字符,连续相同的字符可以同 ...
- Educational Codeforces Round 51 F. The Shortest Statement(lca+最短路)
https://codeforces.com/contest/1051/problem/F 题意 给一个带权联通无向图,n个点,m条边,q个询问,询问两点之间的最短路 其中 m-n<=20,1& ...
- Educational Codeforces Round 12 F. Four Divisors 求小于x的素数个数(待解决)
F. Four Divisors 题目连接: http://www.codeforces.com/contest/665/problem/F Description If an integer a i ...
- Educational Codeforces Round 26 F. Prefix Sums 二分,组合数
题目链接:http://codeforces.com/contest/837/problem/F 题意:如题QAQ 解法:参考题解博客:http://www.cnblogs.com/FxxL/p/72 ...
- Educational Codeforces Round 9 F. Magic Matrix 最小生成树
F. Magic Matrix 题目连接: http://www.codeforces.com/contest/632/problem/F Description You're given a mat ...
随机推荐
- leetcode笔记--7 Find the Difference
question: Given two strings s and t which consist of only lowercase letters. String t is generated b ...
- 使用es6总结笔记
1. let.const 和 block 作用域 在ES6以前,var关键字声明变量.无论声明在何处,都会被视为声明在函数的最顶部(不在函数内即在全局作用域的最顶部). let 关键词声明的变量不具备 ...
- 查看python中包的文档
核心命令:python -m pydoc 查询某包:python -m pydoc 包名 示例: C:\Users\xxx>python -m pydoc pydoc - the Python ...
- Too many open files错误与解决方法
致前辈:该问题的解决思路给了我很大的启发,文章作者Lis, Linux资深技术专家. 问题现象:这是一个基于Java的web应用系统,在后台添加数据时提示无法添加,于是登陆服务器查看Tomcat 日志 ...
- 自测之Lesson6:文件I/O
题目:区分文件I/O和标准I/O. 区别: ①首先两者一个显著的不同点在于,标准I/O默认采用了缓冲机制,比如调用fopen函数,不仅打开一个文件,而且建立了一个缓冲区(读写模式下将建立两个缓冲区), ...
- JavaScript初探系列之面向对象
面向对象的语言有一个标志,即拥有类的概念,抽象实例对象的公共属性与方法,基于类可以创建任意多个实例对象,一般具有封装.继承.多态的特性!但JS中对象与纯面向对象语言中的对象是不同的,ECMA标准定义J ...
- lintcode-189-丢失的第一个正整数
189-丢失的第一个正整数 给出一个无序的正数数组,找出其中没有出现的最小正整数. 样例 如果给出 [1,2,0], return 3 如果给出 [3,4,-1,1], return 2 挑战 只允许 ...
- iOS-根据两个经纬度计算相距距离
CLLocation *orig=[[[CLLocation alloc] initWithLatitude:[mainDelegate.latitude_self doubleValue] long ...
- 3dContactPointAnnotationTool开发日志(十四)
貌似每次让用户手动输入文件路径太不人道了,于是参考Unity 实用教程 之 调用系统窗口选择文件或路径增加了让用户浏览文件的功能,点击输入框旁边的+就可以找到文件并加载进来: 貌似调整位置再计 ...
- 语音信号处理之动态时间规整(DTW)(转)
这学期有<语音信号处理>这门课,快考试了,所以也要了解了解相关的知识点.呵呵,平时没怎么听课,现在只能抱佛脚了.顺便也总结总结,好让自己的知识架构清晰点,也和大家分享下.下面总结的是第一个 ...