QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#500739#6730. CoolbitsPonyHexTL 1ms5588kbC++146.0kb2024-08-01 19:23:362024-08-01 19:23:37

Judging History

你现在查看的是最新测评结果

  • [2024-08-01 19:23:37]
  • 评测
  • 测评结果:TL
  • 用时:1ms
  • 内存:5588kb
  • [2024-08-01 19:23:36]
  • 提交

answer

#define _CRT_SECURE_NO_WARNINGS 1
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#include<random>
#include <chrono>
using namespace std;
std::mt19937_64 rng((std::chrono::steady_clock::now().time_since_epoch().count()));
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define RND mt19937 rnd(0xab8d5f6);
#define time_while(time_while_val) while (((double)clock() - start) / clocks_per_sec < time_while_val)
//#define time_while(time_while_val) while ((double)clock() / clocks_per_sec < time_while_val)//弃
#define rep1(i, n) for(long long i = 1; i <= n; ++i)
#define rep0(i, n) for(long long i = 0; i <= n; ++i)
#define double long double
//#define int long long
//#define ll unsigned long long
#define lc u<<1
#define rc u<<1|1
#define endl "\n"
#define X first
#define Y second
typedef long long ll;
//typedef unsigned long long ull;
typedef pair<int, int> PII;
double PI = acos(-1.0);
const double eps = 1e-9;
const ll maxn = 2e5 + 5;
const ll maxm = 2e17;
const ll inf = 2147483647;
const ll mod = 1e9 + 7;
const int dx[] = { 1,0,-1,0,1,1,-1,-1 };//前4为邻
const int dy[] = { 0,-1,0,1,-1,1,-1,1 };

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

ll ksm(ll a, ll b) {
    ll ans = 1;
    ll base = a;
    while (b) {
        if (b & 1)ans = ans * base % mod;
        base = base * base % mod;
        b >>= 1;
    }
    return ans % mod;
}

ll getinv(ll a) {
    return ksm(a, mod - 2);
}

//dismyth
//警钟长鸣

/*2024/7/29
待补:cdq分治,三维偏序,平衡树->link cut tree*/
/*待补 324(包括f),310,313,315,317*///好多,但是每天得vp,强度得上去
/*306d,344d*/
//赛时多出,赛后少补
//vp一把


/*
struct cmp {
    bool operator()(pair<ll, ll> a, pair<ll, ll>  b) {
        return a.X > b.X;//表示小根堆
    }
};*/

//异或是可叠加的,所以异或是可求前缀和的


//vector<pair<ll, ll> >e;
ll e1[maxn];
ll e2[maxn];
//我们可以尝试把左界的二进制一次性都表示出来然后记录下来
//这样我们每次查询的时候就不会多次计算了
ll n;

inline bool check(ll l, ll r, ll val) {//对于元素val,检查是否在l到r中成立
    if (val > r)return false;
    //这是暴力的跑法,t了,很正常
    //所以我们不应该这样匹配
    //
    //if (r - l + 1 >= val)return true;
    //还是不够,
    //有了,wc我会了,我们判断左界距离这个状态差距有远,然后比较dis
    //就是,把l给扣下来
    //然后,看l的状态变成r需要的dis,r-l满足dis,则成立
    ll mid1 = val;
    ll mid2 = l;
    ll state = 0;
    ll upbound = 1;
    while (mid1) {
        state += (mid2 % 2) * upbound;
        upbound <<= 1;
        mid1 >>= 1;
        mid2 >>= 1;
    }
    //cout << upbound << " " << state << " " << val << endl;
    if (val >= state) {
        ll dis = val - state;
        if (dis <= (r - l))return true;
        else return false;
    }
    else {
        //寻找最小的操作数
        //懂了,这里不对
        //大概就是,
        
        ll newval = 0;
        ll dis = 0;
        ll ex = 1;
        ll mmd = val;
        ll mmmd = state;
        vector<ll>a;
        vector<ll>b;
        while (mmmd) {
            /*
            if (mmd % 2 == 1 && mmmd % 2 == 0) {
                dis += (ex);
            }*/
            a.push_back({ mmd % 2 });
            b.push_back({ mmmd % 2 });
            mmd >>= 1;
            mmmd >>= 1;
        }
        //将两个二进制记录下来,a是要求
        while (a.size()) {
            if (a.back() == 1 && b.back() == 0)break;
            a.pop_back();
            b.pop_back();
        }
        if (a.size()) {
            ll p1 = 0, p2 = 0;
            for (auto p = a.begin(),pp=b.begin(); p != a.end(); p++,pp++) {
                p1 += (*p) * ex;
                p2 += (*pp) * ex;
                ex <<= 1;
            }
            dis = p1 - p2;
        }

        //我说实话,这时候我想直接找最近的转移到的状态是否在范围内,并不好找,好找,但是我不好实现
        //不好不好
        //所以我们去
        //好好,是一样的,都不是很方便,还不如直接上
        //大体的思路就是从第一个位置,开始截取
        //那个位置就是,要求为1,但是确没有1的位置

        //尽力了,用尽手段,但是还是t了,感觉,优化
        //可以,我还能继续优化,做的更好

        if (dis <= (r - l))return true;
        else return false;
    }
    return false;
}

//RND;
void solve() {
    //有了,其实在check函数里,我们每次访问到左界,都进行了操作
    //那一步操作就是去匹配
    //我们没有必要每次都去找那些数
    //可以在进行check之前都处理出来

    cin >> n;
    ll mi = maxm;
    for (int i = 1; i <= n; i++) {
        //ll l, r; cin >> l >> r;
        cin >> e1[i] >> e2[i];
        mi = min(mi, e2[i]);
    }
    ll ans = 0;
    ll t = 32;
    //这个枚举我减少一点,能给我过吗
    ll bd = 0;
    while (mi) {
        mi >>= 1;
        bd++;
    }
    for (ll t = bd; t >= 0; t--) {
        ll md = ksm(2, t);//获取那个位置的数值
        ll mid = ans + md;//检查是否合法
        //首先,不能比右端点大
        bool f = 1;
        for (int i = 1; i <= n; i++) {//对于每个区间,我们检查,当前ans是否合法
            //区间合法的条件,其一,至少区间右界应该大于等于当前的ans
            //f = check(e[i].X, e[i].Y, mid);
            f = check(e1[i], e2[i], mid);
            if (f == 0)break;
        }
        if (f) {
            ans = mid;
        }
    }
    cout << ans << endl;
    //e.clear();
    return;
}

signed main() {
    IOS;
    ll t = 1;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

/*致我已死的友人*/
/*PonyHex*/


详细

Test #1:

score: 100
Accepted
time: 1ms
memory: 5588kb

input:

2
3
0 8
2 6
3 9
1
1 100

output:

6
100

result:

ok 2 number(s): "6 100"

Test #2:

score: -100
Time Limit Exceeded

input:

1117
74
234256176 451122435
614716780 701954053
31102604 284818525
528763990 809400397
40637446 612671528
329403504 936190213
112402633 729525189
248142852 481053286
30877745 700834811
529884578 749041634
146522084 758550567
934650972 996096650
538751855 856147351
170918541 975066425
253153230 35361...

output:

29882460
10439883
79463293
90768686
22491373
11692710
16776650
67341740
18536525
41972008
144137157
42855333
39995541
43488868
44009818
32268396
173845856
22782278
13766220
135007650
39354674
4073141
70831334
70543107
331507485
37817926
43510327
67560240
37521185
76801656
39488739
100671964
60003201...

result: