CF EDU 40 C, D, G 문제 풀이 [사고, 도 론, 이분]
11284 단어 CodeForces 부분 문제 풀이
사고방식: 인접 한 두 수 사이 의 간격 은 반드시 1 또는 y 이다. 그래서 우 리 는 y 만 신경 쓰 고 x 를 신경 쓰 지 않 는 다. 그러면 우 리 는 모든 간격 이 y 인지 아 닌 지 를 직접 체크 하면 된다. 하나의 구덩이 점 은 y = = 3 이 라면 3, 4 는 문제 의 뜻 에 부합 되 지 않 는 다 는 것 이다. 즉, 우리 가 y 를 계산 한 후에 for check 을 해서 이런 상황 을 만들어 야 한 다 는 것 이다.
AC Code
const int maxn = 2e5+5;
int a[maxn];
void solve()
{
int n;
while(cin >> n) {
int flag = 1, y = 1;
for (int i = 1 ; i <= n ; i ++) {
cin >> a[i];
if (i == 1) continue;
if (a[i] == a[i-1]) flag = 0;
if (abs(a[i] - a[i-1]) != 1) y = abs(a[i] - a[i-1]);
}
if (!flag) {
cout << "NO" << endl;
continue;
}
for (int i = 2 ; i <= n ; i ++) {
if (abs(a[i] - a[i-1]) != 1 && abs(a[i] - a[i-1]) != y) {
flag = 0;
break;
}
if (a[i] - a[i-1] == 1 && a[i] % y == 1) {
flag = 0;
break;
}
if (a[i] - a[i-1] == -1 && a[i] % y == 0 && y != 1) {
flag = 0;
break;
}
}
if (!flag) cout << "NO" << endl;
else {
cout << "YES" << endl;
cout << 1000000000 << ' ' << y << endl;
}
}
}
D: 제목: 한 폭 (n, m) 의 그림 을 정 하고 길 이 는 모두 1 입 니 다. 주어진 s, t 는 몇 개의 변 을 더 해서 s 와 t 사이 의 거 리 를 짧 게 할 수 있 습 니까?
사고: n 은 1000 밖 에 없 기 때문에 n ^ 2 의 알고리즘 은 자 연 스 럽 게 생각 했 습 니 다. s, t 에 대해 각각 bfs 를 한 번 씩 진행 하여 다른 점 의 최 단 거 리 를 구 한 다음 에 n ^ 2 는 임 의 두 점 사 이 를 매 거 할 수 있 는 지, i, j 가 추가 할 수 있 는 조건 은 d [s] [i] + d [t] [j] + 1 > = d [s] [t] 입 니 다. 주의 하 는 것 은 매 거 된 순서 원인 때 문 입 니 다. 그래서 s, t 와 이 두 점 사이 의 최 단 거 리 는 min 을 가 져 야 합 니 다.구체 적 으로 코드 실현 을 보십시오.
AC Code
const int maxn = 1e3+5;
int n, m;
int d[2][maxn], mapp[maxn][maxn];
bool vis[maxn];
vector<int>g[maxn];
void bfs(int st, int f) {
queue q; Fill(vis, 0);
q.push({st, 0}); vis[st] = 1;
while(!q.empty()) {
pii u = q.front();
q.pop();
for (int i = 0 ; i < sz(g[u.fi]) ; ++ i) {
int to = g[u.fi][i];
if (vis[to]) continue;
vis[to] = 1;
d[f][to] = u.se + 1;
q.push({to, u.se+1});
}
}
}
void solve()
{
int s, t;
scanf("%d%d%d%d", &n, &m, &s, &t);
for (int i = 1 ; i <= m ; i ++) {
int u, v;
scanf("%d%d", &u, &v);
mapp[u][v] = mapp[v][u] = 1;
g[u].pb(v);
g[v].pb(u);
}
bfs(s, 0); bfs(t, 1); int ans = 0;
for (int i = 1 ; i <= n ; ++ i) {
for (int j = 1 ; j <= n ; ++ j) {
if (i == j || mapp[i][j]) continue;
if (min(d[0][j] + d[1][i], d[0][i] + d[1][j]) + 1 >= d[0][t]) {
++ ans;
}
}
}
printf("%d
", ans/2);
}
G: 제목: n 조 벽 이 있 고 벽 에 궁수 가 있 으 며 그들 이 사격 할 수 있 는 범 위 를 제시 한 다음 에 준비 한 k 개 궁수 가 있 습 니 다. 이 n 조 벽의 최소 방어 치가 얼마 인지 물 어보 세 요. 방어 치 는 벽의 궁수 수량 으로 정의 되 고 모든 n 조 벽 에 있 는 궁수 가 min 을 취 하 는 것 이 바로 이 n 조 벽의 최소 방어 치 입 니 다.
사고: 물론 2 분 의 답 입 니 다. 그러면 어 려 운 점 은 check 입 니 다. 하나의 사례 를 내 면 주로 해결 하 는 문 제 를 알 수 있 습 니 다. 3, 1, 1000, 00 이라는 답 은 1000 입 니 다. 1000 명의 궁수 들 을 모두 두 번 째 벽 에 놓 아야 합 니 다. 그래서 이 예 를 통 해 우 리 는 추 가 된 궁수 들 을 최대한 경계 맨 오른쪽 에 두 어야 한 다 는 것 을 알 수 있 습 니 다.그래서 우 리 는 한 구간 r 의 합 을 지 키 고 매번 우리 의 2 분 의 답 과 현재 벽 에 있 는 궁수 의 수량 관 계 를 계산 한 다음 에 2 분 의 답 에 도달 해 야 하 는 추가 궁수 를 판단 한 다음 에 k 와 의 관 계 를 판단 하면 된다. 하 나 는 틀림없이 이 숫자 가 매우 클 것 이 고 롱 롱 롱 롱 이 터 지면 마이너스 가 될 것 이다.판단 에 영향 을 줄 수 있 습 니 다. k 최대 1e 18 이기 때문에 추가 궁수 수가 1e 18 을 초과 하면 1e 18 + 5 와 min 을 취하 면 불가능 함 을 표시 합 니 다. 구체 적 인 세부 사항 은 코드 를 보십시오.
AC Code
const int maxn = 5e5+5;
ll a[maxn], tmp[maxn];
ll n, len, k;
ll ok(ll u) {
memcpy(tmp, a, sizeof(a));
ll now = 0, s = 0;
for (int i = 1 ; i <= len ; i ++) now += a[i];
for (int i = 1 ; i <= n ; i ++) {
now += i+len>n?0:tmp[i+len];
now -= i-len-1<0?0:tmp[i-len-1];
if (now < u) {
tmp[min(n, i+len)] += u - now;
s = min(s + u - now, INF+5);
now = u;
}
}
return s;
}
void solve()
{
while(~scanf("%lld%lld%lld", &n, &len, &k)) {
for (int i = 1 ; i <= n ; i ++) {
scanf("%lld", &a[i]);
}
ll l = 0, r = (1ll<<60), mid, ans = 0;
while(l <= r) {
mid = (l + r) >> 1;
if (ok(mid) <= k) {
ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
printf("%lld
", ans);
}
}