codeforces round#524 D - Olya and magical square /// 大概算是数学规律题?

题目大意:

t 个测试用例  (1≤t≤103)

给定n k  (1≤n≤10^9,1≤k≤10^18)

表示有一个边长为2^n的正方形格子 每次操作只能将一个格子切割为左上左下右上右下的四等分格子

问进行k次四等分切割后 能否使得 左下角的格子的边长 和 右上角的格子的边长 相等

并且存在一条左下角格子到右上角格子的路径上 经过的格子的边长 也和它们相等

若可以输出 “YES 切割后的log2(边长)” 若操作次数用不完输出“NO”

首先

对边长为2^1的格子四等分切割为1*1小格需要         1          次操作

对边长为2^2的格子四等分切割为1*1小格需要   1*4+1=5   次操作

对边长为2^3的格子四等分切割为1*1小格需要  5*4+1=21  次操作

......op[ i ] = op[ i-1 ] * 4 + 1

由此可预处理出边长为 2^i 的格子切割为1*1小格 需要 op[i] 次操作

然后我们可以发现当切割边长为2^31的格子时 op[31] 即操作次数超出了k的范围10^18

(k最大时不足以将一个2^31边长的格子切为1*1小格)

假设 边长为2^32时 先进行一次操作(分为四格2^31) 剩k-1次操作

之后只对右下的2^31的一格切割 那么k-1次操作绝对能用完

所以路径由左下经左上到右上 经过的三格的边长一样都是2^31 即输出log2(2^31)=31

以此类推 >31 的情况 只要这么处理 答案就是 n-1

n>=31时 ?考虑只切我们要走的路径的格子(假设我们走左边和上边的边缘圈的格子)

每次只对边缘圈的格子切割一次

第一次需要切割 1 格 (即切1次) (路径格子边长减为 2^(n-1) )

第二次需要切割 3 格 (即切3次) (路径格子边长减为 2^(n-2) )

第三次需要切割 7 格 (即切7次) (路径格子边长减为 2^(n-3) )

......

每次递推可得到下次需要切割的格子数 now(下次) = now(本次) * 2 + 1

累加得到边缘圈应切割次数 tot += now

但是仅仅只切割外围 k次操作很可能还是用不完的

那么此时我们考虑每次切割后不会成为外围圈的格子

因为它们不会影响到我们要走的路径 所以可以直接把它们切成1*1的小格

第一次红色格子可切割 共需切割次数 op[ n-1 ] * (3-2)

第二次绿色格子可切割 共需切割次数 op[ n-2 ] * (7-2)

第三次青色格子可切割 共需切割次数 op[ n-3 ] * (15-2)

.....(由于恰好对应下次切割要切割的外围圈格子往内的一圈 往内一圈会少两格 所以恰好是 now(下次)-2 格)

累加得到额外可切割次数 re

那么当只切外围圈的操作数 tot >= k 时 可得到答案

或者 当切外围也切内圈 tot+re>=k 时 也可得到答案

否则 k次操作 就不可能被用完

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k,op[100];
int main(){
    for(int i=1;i<=31;i++) op[i]=op[i-1]*4LL+1LL;
    int t; scanf("%d",&t);
    while(t--){
        scanf("%I64d%I64d",&n,&k);
        if(n>31) {
            printf("YES %I64d\n",n-1);
            continue;
        }
        ll tot=0,now=1,j=0,re=0;
        while(now+tot<=k&&j<n){
            tot+=now;
            now=now*2+1; // now更新为下轮操作需要操作的边缘圈的格数
            j++; // 对边缘圈的小格各操作一次 那么每格的边长又小了一半 即由2^(n-j)变为2^(n-(j+1))
            re+=op[n-j]*(now-2);
        }
        if(k>tot+re) printf("NO\n"); // 全部切到1*1小格的操作次数tot+re 仍然不够k次
        else printf("YES %I64d\n",n-j); // n-j 即缩小到最后的 log2(边长)
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zquzjx/p/10014496.html

时间: 2024-08-07 06:59:19

codeforces round#524 D - Olya and magical square /// 大概算是数学规律题?的相关文章

Codeforces Round #384 (Div. 2) B. Chloe and the sequence(规律题)

传送门 Description Chloe, the same as Vladik, is a competitive programmer. She didn't have any problems to get to the olympiad like Vladik, but she was confused by the task proposed on the olympiad. Let's consider the following algorithm of generating a

Codeforces Round #249 (Div. 2) A. Black Square

水题 #include <iostream> #include <vector> #include <algorithm> using namespace std; int main(){ vector<int> a(4); cin >> a[0] >> a[1]>>a[2]>>a[3]; string str; cin >> str; int res = 0; for(int i = 0 ; i

Codeforces Round #524 (Div. 2) B. Margarite and the best present

B. Margarite and the best present 题目链接:https://codeforces.com/contest/1080/problem/B 题意: 给出一个数列:an=(-1)n,之后有询问,问 [l,r] 之间的ai和为多少. 题解:这个分情况讨论一下就可以了,区间长度的奇偶数丶左端点的奇偶数. 代码如下: #include <cstdio> #include <cstring> #include <algorithm> #include

Codeforces Round #524 (Div. 2) codeforces 1080A~1080F

目录 codeforces1080A codeforces 1080B codeforces 1080C codeforces 1080D codeforces 1080E codeforces 1080F codeforces1080A 传送门:https://codeforces.com/contest/1080/problem/A 题意:制造一份邀请函需要2份a物品,5份b物品,8份c物品,一个盒子里面有k份物品(可以为a或b或c)问你制造n份邀请函需要用多少个盒子 题解:直接加起来就行

Codeforces Round #599 (Div. 2) A. Maximum Square

Ujan decided to make a new wooden roof for the house. He has nn rectangular planks numbered from 11 to nn. The ii-th plank has size ai×1ai×1 (that is, the width is 11 and the height is aiai). Now, Ujan wants to make a square roof. He will first choos

Codeforces Round #524 (Div. 2)D - TV Shows

题意是给你n个节目,每次租一台电视需要消耗x+(r-l)*y元,问你怎么样安排才能使得看完所有节目并且消费最少,输出最少的金额 做法是按节目开始时间l排序,遍历所有节目,如果该节目不能在已有的电视上播放或者在已有的电视上播放消耗比再去借一台更多的时候, 那么就再去借一台电视机,当有多个电视机可以播放的时候,贪心选择r最大的电视机.由于是按l升序排序,当(tv[i].l-r)*y>x的时候则表明此时 用已有的电视机播放不如再去借一台,而剩下的l只会更大,所以要erase当前的电视机,否则会超时.P

Codeforces Round #524 (Div.2)题解

题解 CF1080A [Petya and Origami] 这道题其实要我们求的就是 \[\lceil 2*n/k \rceil + \lceil 5*n/k \rceil + \lceil 2*n/k \rceil\] 然后就做完了 # include <bits/stdc++.h> # define ll long long int main() { ll n, k; scanf("%lld%lld", &n, &k); ll ans = ((2 *

Codeforces Round #524 (Div. 2) C. Masha and two friends

C. Masha and two friends 题目链接:https://codeforc.es/contest/1080/problem/C 题意: 给出一个黑白相间的n*m的矩阵,现在先对一个子矩阵颜色变为白色,然后再对一个子矩阵颜色变为黑色,问最终白色格子和黑色格子有多少? 题解: 定义w(a,b)为(1,1)到(a,b)中白色的数量,通过观察找规律可以发现w(a,b)=((b+1)/2)*((a+1)/2)+(b/2)*(a/2). 然后b(a,b)就是格子总数量减去w(a,b). 现

Codeforces Round #524 (Div. 2)

好不容易考完电路,又可以回来刷题了,只是现在恐怕码力连新生都比不上了. A Petya and Origami 开头就是一大水题,意思就是制作一张贺卡需要几张什么颜色的纸,一共做n份,一叠纸有k张纸,问你需要几叠纸. 1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 int main() 5 { 6 int n,k; 7 scanf("%d%d",&n,&k); 8 p