题意:给两个长度为n的序列(a1,a2......,an)、(b1,b2......bn)和m个询问以及一个整数k,找出满足k <= S(t) = Σ(i=1 to n) ((t-bi) / ai)向下取整 的最小t。考虑函数的单调性此题可以二分,对于该式子可以证明 ((t-bi) / ai)向下取整的值就是 (t/ai)向下取整的值减去 (bi/ai)向下取整的值 如果 (t%ai) - (bi%ai) 的值比0小,说明还得到前面算出来的(t/ai)的值那里拿一个1来减, 所以算出来的值应该减1。 考虑a的值小于1000,用1000个树状数组维护每个(bi % ai)的前缀和,用一个大小为1000的数组nums维护每个ai出现的次数,用一个变量sum记录Σ(i=1 to n)bi/ai的和,则对于每个t,S(t)可以通过以下方式计算得到:i从for 1到1000 记录(t/i) * nums[ai]的值,这个值减去sum得到的是未经过取余处理的值,然后i 从1for到1000的过程中可以减去 (bi %ai)比(t%i)大的个数,这个数可以通过树状数组查询(getsum(t%ai))表示查找<=t%ai的数 然后用总个数nums[ai]减去它得到。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1e3+10; 5 const int maxm = 1e5+10; 6 int t,n,m,op; 7 ll x,y,k; 8 ll a[maxm],b[maxm]; 9 int nums[maxn]; 10 int lowbit(int x) {return x&(-x);} 11 struct tree{ 12 int c[maxn]; 13 inline void update(int x,int y){ 14 x++; 15 for(int i=x;i<maxn;i+=lowbit(i)) 16 c[i] += y; 17 } 18 inline int getsum(int x){ 19 int ans = 0;x++; 20 for(int i=x;i;i-=lowbit(i)) 21 ans += c[i]; 22 return ans; 23 } 24 }node[maxn]; 25 bool check(ll t){ 26 ll tmp = 0; 27 for (int i = 1; i <= 1000; i++){ 28 tmp += (t / i) * nums[i] - (nums[i] - node[i].getsum(t % i)); 29 if (tmp >= k + 1000 - i) return true; 30 } 31 return tmp >= k; 32 } 33 int main(){ 34 scanf("%d",&t); 35 while (t--){ 36 ll sum = 0; 37 memset(nums, 0, sizeof nums); 38 memset(node, 0, sizeof node); 39 scanf("%d%d",&n,&m); 40 for (int i = 1; i <= n; i++){ 41 scanf("%lld",&a[i]); 42 nums[a[i]]++; 43 } 44 for (int i = 1; i <= n; i++){ 45 scanf("%lld",&b[i]); 46 sum += b[i] / a[i]; 47 node[a[i]].update(b[i]%a[i],1); 48 } 49 while (m--){ 50 scanf("%d",&op); 51 if (op == 1){ 52 scanf("%lld%lld",&x,&y); 53 nums[a[x]]--,nums[y]++; 54 node[a[x]].update(b[x] % a[x], -1); 55 node[y].update(b[x] % y, 1); 56 sum = sum - b[x] / a[x] + b[x] / y; 57 a[x] = y; 58 } 59 else if (op == 2){ 60 scanf("%lld%lld",&x,&y); 61 node[a[x]].update(b[x]%a[x], -1); 62 node[a[x]].update(y%a[x], 1); 63 sum = sum - b[x] / a[x] + y / a[x]; 64 b[x] = y; 65 } 66 else{ 67 scanf("%lld",&k); 68 ll l = 0, r = 1e12, ans; 69 k += sum; 70 while (l <= r){ 71 ll mid = (l + r) >> 1; 72 if (check(mid)) { 73 ans = mid; 74 r = mid-1; 75 } 76 else l = mid + 1; 77 } 78 printf("%lld ",ans); 79 } 80 } 81 } 82 return 0; 83 }