# Gori#017(ABC037)
# B - 編集
# 概要
全要素がで長さの数列がある.
この数列に対して, 以下の操作を回行った結果の数列を出力せよ.
- 数列の番目から番目をに書き換える.
# 解法
制約がかつなので, O(NQ)でも間に合う.
したがって, 愚直に回だけ数列の番目から番目をに書き換えれば良い.
#include <bits/stdc++.h>
using namespace std;
int main() {
int N,Q; cin >> N >> Q;
vector<int> a(N,0);
while(Q--){
int l,r,t; cin>>l>>r>>t;
for(int i=l-1;i<r;++i){
a[i] = t;
}
}
for(int i=0;i<N;++i){
cout << a[i] << endl;
}
return 0;
}
# C - 総和
長さの数列が与えられたとき, 長さの連続する部分列の総和を求めよ.
e.g.)
4 3
1 2 4 8
この場合は,
(1+2+4) + (2+4+8) = 21
となる.
# 解法
累積和を取って, を求めれば良い.
#include <bits/stdc++.h>
using namespace std;
using int64 = int64_t;
#define int int64
signed main() {
int n,k; cin >> n >> k;
vector<int> a(n);
for(int i=0;i<n;++i) cin >> a[i];
vector<int> sm(n+1,0);
for(int i=0;i<n;++i){
sm[i+1] += sm[i] + a[i];
}
int ans = 0;
for(int i=0;i<=n-k;++i){
ans += sm[i+k] - sm[i];
}
cout << ans << endl;
return 0;
}
# D - 経路
のそれぞれのマス目に整数が書いてある.
あなたは, そのうちの任意のマスから以下の制約を満たした時のみ動けるとき, 移動経路の総和をで割ったあまりを求めよ.ただし, その場から動かないものも移動経路の1つとする.
- 今いるマスの上下左右に隣接しているマスで, 今いるマスよりも大きな整数が書かれたマスに移動できる.
# 解法
遷移が上下左右に限られるので, DPっぽいことが分かる.
ここで, 任意のマスについて考えると, への移動経路は,
- からの経路
- からの経路
- からの経路
- からの経路 のみであることが分かる( 移動できるのは, 今いるマスの上下左右に隣接しているマスのみ).
制約は, なので, でも高々に落ち着き, メモ化すれば計算量は抑えられる.
#include <bits/stdc++.h>
using namespace std;
using int64 = int64_t;
#define int int64
constexpr int MOD = 1e9 + 7;
int H,W;
int a[1010][1010];
int memo[1010][1010];
int f(int hi, int wi){
if (memo[hi][wi] > 0) return memo[hi][wi];
int sm = 0;
if (hi>0 && a[hi-1][wi]>a[hi][wi]) (sm += f(hi-1,wi)) %= MOD;
if (hi+1<H && a[hi+1][wi]>a[hi][wi]) (sm += f(hi+1,wi)) %= MOD;
if (wi>0 && a[hi][wi-1]>a[hi][wi]) (sm += f(hi,wi-1)) %= MOD;
if (wi+1<W && a[hi][wi+1]>a[hi][wi]) (sm += f(hi,wi+1)) %= MOD;
return (memo[hi][wi] = sm + 1) %= MOD;
}
signed main(){
cin>>H>>W;
for(int hi=0;hi<H;++hi){
for(int wi=0;wi<W;++wi){
cin >> a[hi][wi];
}
}
int ans = 0;
for(int hi=0;hi<H;++hi){
for(int wi=0;wi<W;++wi){
(ans += f(hi,wi)) %= MOD;
}
}
cout << ans << endl;
return 0;
}
以上.
お疲れ様でした.