codeforce 1400
COFO::1462D Add to Neighbour and Remove
cofo problem
COFO::1462D Add to Neighbour and Remove
Problem
- level : 1400
- tag : greedy, math, number theory
- TIME
- u : 5
- a : 60
- c : 5
- d : 20
- e : 10
- 3010 * 3010을 매번 초기화 시키는 코드를 넣었더니 TLE를 받아서 여러번 try끝에 원인을 찾아냈습니다.
Point
- n과 n개의 수로 이루어진 배열 a가 주어집니다.
- 다음과 같은 작업을 최대 n-1번 진행할 수 있을때, 최소 작업의 수로 남은 원소가 모두 같은 수가 되게 하고, 이때의 작업수를 출력합니다.
- a[i]를 a[i-1] 혹은 a[i+1]에 더하고, a[i]를 erase합니다.
Design
- O(N^2) 방법이 도저히 생각안나다가, DP를 다른 각도에서 보게되었고 이를 통해 해결할 수 있었습니다.
- 시작점과 끝점이 다른 N^2짜리 연속합을 미리 구해둡니다.
- 그리고 다음과 같은 초기값으로 함수를 실행합니다.
- v = 0번째부터 0번째까지의 합
- v = 0번째부터 1번째까지의 합
- …
- v = 0번째부터 n-1번째까지의 합
- 위와 같이 v값을 설정하고, 함수에 보낸후, 연속합이 v와 같게 만들 수 있는지 여부를 판단하면 됩니다.
Complexity
- O(N^2)
Code
#include<iostream>
#include<vector>
#include<queue>
#include<map>
#include<math.h>
#include<algorithm>
#define rep(i,a,b) for(LL i=(a);i<(b);i++)
#define r_rep(i,a,b) for(LL i=(a);i>(b);i--)
typedef long long int LL;
using namespace std;
LL n;
LL a[3010];
LL SUM[3010][3010];
LL mn;
LL findRange(LL v, LL id, LL cnt){
if(mn < cnt) return n-1;
if(id == n) return cnt;
LL bst = n;
rep(i, id, n){
if(SUM[id][i] == v){
LL ret = findRange(v, i+1, cnt + (i - id));
if(ret < bst) bst = ret;
}else if(SUM[id][i] > v) break;
}
mn = min(mn, bst);
return bst;
}
LL solve(){
//rep(i, 0, 3010) rep(j, 0, 3010) SUM[i][j] = 0;
cin >> n;
rep(i, 0, n) cin >> a[i];
bool f = true;
rep(i, 0, n-1){
if(a[i] != a[i+1]){ f = false; break;}
}
if(f){
return 0;
}
rep(st, 0, n){
SUM[st][st] = a[st];
rep(en, st+1, n){
SUM[st][en] = SUM[st][en-1] + a[en];
}
}
mn = n-1;
LL bst = n-1;
rep(i, 0, n-1){
LL ret = findRange(SUM[0][i], i+1, i);
if(bst > ret) bst = ret;
}
return bst;
}
int main(){
cin.tie(nullptr);
cout.tie(nullptr);
// freopen("input.txt", "r", stdin);
int tc; cin >> tc;
while(tc--)
cout << solve() << '\n';
}