Educational Codeforces Round 85

题目链接

http://codeforces.com/contest/1334/problem/D

tag

构造,模拟

solution

题目要求出在有向完全图中找到一个遍历所有边所经过点编号字典序最小的环的第(L-R)位,字典序最小,容易想到贪心的构造,每次出边都选择未访问过的编号最小的点,又要构成环,因而最后一个访问的点是1,例(n = 5), 字典序最小的环为(1->2->1->3->1->4->1->5->2->3->2->4->2->5->3->4->3->5->4->5->1),不难发现,由编号(i)出发可以到达的点有(n-i)个,这条子路径共有(2*(n-i))个点,对于第(i)条子路经的第(j)个点编号,若(j)为偶数,则(path[i][j] = i + j / 2), 否则(path[i][j] = i),我们可以模拟这个贪心过程,但最多有(n*(n-1) + 1)个点,当(n=10^5),模拟复杂度过大,由于题目要求的是(L-R)位的点的编号,而(R-L leq 10^5),所以我们需要定位第(L)个数的位置,通过二分可以找到(L)是从编号几所到达的点,并可计算出(L)为该编号所到达的第几个点,然后我们就可以直接模拟这个贪心构造的过程,另外需要注意特判是否已经到达了最后一个点

code

//created by pyoxiao on 2020/07/07
#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define CL(a, b) memset(a, b, sizeof(a))
using namespace std;
const int mod = 1e9 + 7;
LL fpow(LL a, LL b, LL p = mod){LL ans = 1; a %= p; while(b) {if(b & 1) ans = ans * a % p; b >>= 1; a = a * a % p;} return ans;}
LL gcd(LL a, LL b){return b == 0 ? a : gcd(b, a % b);}
const int N = 1e5+ 7;
int n;
LL L, R;
vector<LL> ans;
void solve() {
    scanf("%d %lld %lld", &n, &L, &R);
    int l = 0, r = n, tmp = -1;
    while(l <= r) {
        int mid = l + r >> 1;
        if(1LL * (2 * n - mid - 1) * mid < L) {
            l = mid + 1;
            tmp = mid;
        } else {
            r = mid - 1;
        }
    }
    //cout << tmp << '
';
    LL num = L - 1LL * (2 * n - tmp - 1) * tmp;
    int flag = 1;
    if(num & 1) flag = 0;
    tmp ++;
    while(L <= R) {
        if(L == 1LL * n * (n - 1) + 1) {ans.pb(1); break;}
        if(!flag) ans.pb(tmp);
        else ans.pb(tmp + (L - 1LL * (2 * n - tmp) * (tmp - 1) + 1) / 2);
        flag ^= 1; L ++;
        if(L > 1LL * (2 * n - tmp - 1) * tmp) tmp ++;
    }
    for(auto it : ans) printf("%d ", it);
    puts("");
    ans.clear();
}
int main() {
    int T = 1;
    scanf("%d", &T);
    while(T --) 
        solve();
    return 0;
}
原文地址:https://www.cnblogs.com/pyoxiao/p/13261874.html