zoukankan      html  css  js  c++  java
  • 【数据结构】【CF1073D】 Berland Fair

    Description

    给定 (n) 个商店,他们围成一个圆圈,按照顺时针从 (1)(n) 编号。你有 (T) 元钱,从 (1) 号点开始按照顺时针方向走,每到一个商店,只要钱够就必须买这个商店的物品。商店中物品是无限的,即多次到达可能多次购买。求会买多少件物品

    Input

    第一行是一个整数 (n)

    下面一行 (n) 个整数 (a_i),代表每个商店物品的价格

    Output

    一行一个整数代表答案

    Hint

    (1~leq~n~leq~2~ imes~10^5~,~1~leq~T~leq~10^{18}~,~1~leq~a_i~leq~10^9)

    Solution

    解法一:

    显然在钱数充足是我们可以直接除一下得到我们可以转多少圈,(O(1)) 统计这部分答案,然后把钱数取模即为这些圈转完后我们剩下的钱,这时的钱数是不足以转完一圈的。

    下面我们考虑用这些钱可以连续走多远,即会到哪一个商店停下来。注意到这个值是可以二分的,具体的,我们维护一个前缀和,二分哪个位置的前缀和是最大的小于钱数的即可。然后剩下那个位置的商店显然再也不会被购买到了,于是可以将它直接删去,然后统计这一段连续走的位置的答案。删除这个位置后的前缀和可以用树状数组或线段树维护,一段区间中还剩多少个没有被删去的位置也可以树状数组维护。对于这个位置后面能连续走到哪里,我们依然可以二分这个值,以此类推直到一圈走完,然后从头开始重复流程即可。

    注意到每次二分我们一定会删除一个位置,所以我们会二分 (O(n)) 次,直接二分+树状数组/线段树的话,单次二分复杂度 (O(log^2 n)),总复杂度 (O(n log^2 n))。如果在线段树上二分,单次复杂度可以做到 (O(log n)),总复杂度 (O(n log n))

    但是天知道为什么我的两个log算法跑的比一个log的还快

    解法二:

    算出当前的钱数可以走多少圈的方法同上,然后考虑我们暴力跑一圈,统计有哪些位置的是不能被购买到的,直接删掉。然后用剩下的钱再取模。

    注意到 (T) 每次取模时的模数一定小于 (T),而一个数被比自己小的数取模至少减少二分之一,证明上可以分模数大于或小于等于 (frac{m}{2}) 进行讨论。于是 (T) 被取模 (O(log T)) 次,每次对应一次 (O(n)) 的统计答案,于是总复杂度 (O(n log T))

    Code

    依据解法一写成。

    (O(n log^2n))

    #include <cstdio>
    #ifdef ONLINE_JUDGE
    #define freopen(a, b, c)
    #endif
    #define rg register
    #define ci const int
    #define cl const long long
    
    typedef long long  ll;
    
    namespace IPT {
    	const int L = 1000000;
    	char buf[L], *front=buf, *end=buf;
    	char GetChar() {
    		if (front == end) {
    			end = buf + fread(front = buf, 1, L, stdin);
    			if (front == end) return -1;
    		}
    		return *(front++);
    	}
    }
    
    template <typename T>
    inline void qr(T &x) {
    	rg char ch = IPT::GetChar(), lst = ' ';
    	while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
    	while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
    	if (lst == '-') x = -x;
    }
    
    template <typename T>
    inline void ReadDb(T &x) {
    	rg char ch = IPT::GetChar(), lst = ' ';
    	while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
    	while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
    	if (ch == '.') {
    		ch = IPT::GetChar();
    		double base = 1;
    		while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
    	}
    	if (lst == '-') x = -x;
    }
    
    namespace OPT {
    	char buf[120];
    }
    
    template <typename T>
    inline void qw(T x, const char aft, const bool pt) {
    	if (x < 0) {x = -x, putchar('-');}
    	rg int top=0;
    	do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
    	while (top) putchar(OPT::buf[top--]);
    	if (pt) putchar(aft);
    }
    
    const int maxn = 200010;
    
    int n;
    ll t, ans;
    int MU[maxn];
    ll tree[maxn], val[maxn];
    
    inline int lowbit(ci x) {return x & (-x);}
    
    ll ask(ll*, int);
    int check(int, ll);
    void update(ll*, int, ci);
    
    signed main() {
    	freopen("1.in", "r", stdin);
    	qr(n); qr(t);
    	for (rg int i = 1; i <= n; ++i) {qr(MU[i]); update(tree, i, MU[i]); update(val, i, 1);}
    	ll s = ask(tree, n); int cnt = n;
    	while (cnt) {
    		if (!t) break;
    		ans += t / s * cnt; t %= s;
    		int k = 0;
    		do {
    			int pre = k;
    			k = check(k, t);
    			if (k > n) {
    				t -= ask(tree, n) - ask(tree, pre);
    				ans += ask(val, n) - ask(val, pre);
    				break;
    			};
    			update(tree, k, -MU[k]); update(val, k, -1); --cnt;
    			t -= ask(tree, k - 1) - ask(tree, pre);
    			s -= MU[k];
    			ans += ask(val, k) - ask(val, pre);
    		} while (cnt && t);
    	}
    	qw(ans, '
    ', true);
    }
    
    void update(ll *ar, int x, ci v) {
    	while (x <= n) {
    		ar[x] += v;
    		x += lowbit(x);
    	}
    }
    
    ll ask(ll* ar, int x) {
    	ll _ret = 0;
    	while (x) {
    		_ret += ar[x];
    		x -= lowbit(x);
    	}
    	return _ret;
    }
    
    int check(int pre, ll x) {
    	int l = pre, r = n + 1, mid = l, _ret = 0;
    	while (l <= r) {
    		mid = (l + r) >> 1;
    		if ((ask(tree, mid) - ask(tree, pre)) <= x) _ret = mid, l = mid + 1;
    		else r = mid - 1;
    	}
    	return _ret + 1;
    }
    

    (O(n log n))

    #include <ctime>
    #include <cstdio>
    #ifdef ONLINE_JUDGE
    #define freopen(a, b, c)
    #endif
    #define rg register
    #define ci const int
    #define cl const long long
    
    typedef long long ll;
    
    namespace IPT {
    	const int L = 1000000;
    	char buf[L], *front=buf, *end=buf;
    	char GetChar() {
    		if (front == end) {
    			end = buf + fread(front = buf, 1, L, stdin);
    			if (front == end) return -1;
    		}
    		return *(front++);
    	}
    }
    
    template <typename T>
    inline void qr(T &x) {
    	rg char ch = IPT::GetChar(), lst = ' ';
    	while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
    	while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
    	if (lst == '-') x = -x;
    }
    
    template <typename T>
    inline void ReadDb(T &x) {
    	rg char ch = IPT::GetChar(), lst = ' ';
    	while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
    	while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
    	if (ch == '.') {
    		ch = IPT::GetChar();
    		double base = 1;
    		while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
    	}
    	if (lst == '-') x = -x;
    }
    
    namespace OPT {
    	int buf[120];
    }
    
    template <typename T>
    inline void qw(T x, const char aft, const bool pt) {
    	if (x < 0) {x = -x, putchar('-');}
    	rg int top=0;
    	do {OPT::buf[++top] = int(x % 10 + '0');} while (x /= 10);
    	while (top) putchar(OPT::buf[top--]);
    	if (pt) putchar(aft);
    }
    
    const int maxn = 200010;
    const int maxt = 400010;
    
    int n;
    ll t, ans;
    int tree[maxn], MU[maxn];
    
    struct Tree {
    	Tree *ls, *rs;
    	int l, r;
    	ll v;
    	
    	inline void pushup() {
    		this->v = this->ls ? (this->rs ? this->ls->v + this->rs->v : this->ls->v) : this->rs->v;
    	}
    };
    Tree *pool[maxt], qwq[maxt], *rot;
    int top;
    
    inline int lowbit(ci x) {return x & -x;}
    
    int check(int, ll);
    void buildpool();
    void build(Tree*, ci, ci);
    void update(int, ci);
    void update(Tree*, ci);
    ll ask(Tree*, ci, ci);
    int ask(int);
    int ask(Tree*, cl);
    
    signed main() {
    	freopen("1.in", "r", stdin);
    	qr(n); qr(t); ll s = 0; 
    	for (rg int i = 1; i <= n; ++i) {qr(MU[i]); s+= MU[i]; update(i, 1);}
    	int cnt = n;
    	buildpool();
    	build(rot, 1, n);
    	while (cnt) {
    		if (!t) break;
    		ans += t / s * cnt; t %= s;
    		int k = 0;
    		do {
    			int pre = k;
    			k = check(k, t);
    			if (k > n) {
    				t -= ask(rot, pre + 1, n);
    				ans += ask(n) - ask(pre);
    				break;
    			};
    			update(rot, k); update(k, -1); --cnt;
    			t -= ask(rot, pre, k - 1);
    			s -= MU[k];
    			ans += ask(k) - ask(pre);
    		} while (cnt && t);
    	}
    	qw(ans, '
    ', true);
    }
    
    
    int check(int pre, ll x) {
    	x += ask(rot, 1, pre);
    	ll s = ask(rot, 1, n);
    	if (s <= x) return n + 1;
    	return ask(rot, x);
    }
    
    void buildpool() {
    	for (rg int i = 0; i < maxt; ++i) pool[i] = qwq + i;
    	rot = pool[maxt - 1];  top = maxt - 2;
    }
    
    void build(Tree *u, ci l, ci r) {
    	u->l = l; u->r = r;
    	if (l == r) {u->v = MU[l]; return;}
    	int mid = (l + r) >> 1;
    	if (l <= mid) build(u->ls = pool[top--], l, mid);
    	if (mid < r) build(u->rs = pool[top--], mid + 1, r);
    	u->pushup();
    }
    
    void update(int x,ci v) {
    	while (x <= n) {
    		tree[x] += v;
    		x += lowbit(x);
    	}
    }
    
    void update(Tree* u, ci x) {
    	if ((u->l > x) || (u->r < x)) return;
    	if (u->l == u->r) {u->v = 0; return;}
    	if (u->ls) update(u->ls, x);
    	if (u->rs) update(u->rs, x);
    	u->pushup();
    }
    
    int ask(int x) {
    	int _ret = 0;
    	while (x) {
    		_ret += tree[x];
    		x -= lowbit(x);
    	}
    	return _ret;
    }
    
    ll ask(Tree *u, ci l, ci r) {
    	if ((u->l > r) || (u->r < l)) return 0;
    	if ((u->l >= l) && (u->r <= r)) return u->v;
    	return u->ls ? (u->rs ? ask(u->ls, l, r) + ask(u->rs, l, r) : ask(u->ls, l, r)) : ask(u->rs, l, r);
    }
    
    int ask(Tree *u, cl v) {
    	if (u->l == u->r) return u->l;
    	if (u->ls->v <= v) return ask(u->rs, v - u->ls->v);
    	else return ask(u->ls, v);
    }
    

    Summary

    该define int ll就要define啊= =要不然可能会fst的很惨= =

    一个数对比自己小的数取模一次至少减少一半。

  • 相关阅读:
    HAproxy 1.5 dev14 发布
    IBM/DW 使用 Java 测试网络连通性的几种方法
    Skype 4.1 Linux 发布,支持微软帐号登录
    Dorado 7.1.20 发布,Ajax的Web开发平台
    Aspose.Slides for Java 3.0 发布
    开发版本 Wine 1.5.18 发布
    BitNami Rubystack 开始支持 Ruby 2.0
    XWiki 4.3 正式版发布
    Silverlight实例教程 Out of Browser的Debug和Notifications窗口
    Silverlight实例教程 Out of Browser与Office的互操作
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10220109.html
Copyright © 2011-2022 走看看