URAL 2052 Physical Education

题目链接:https://vjudge.net/contest/254142#problem/G

参考题解:https://blog.csdn.net/zearot/article/details/47984379

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long
  4 #define LL __int128
  5 #define ull unsigned long long
  6 #define mst(a,b) memset((a),(b),sizeof(a))
  7 #define mp(a,b) make_pair(a,b)
  8 #define pi acos(-1)
  9 #define pii pair<int,int>
 10 #define pb push_back
 11 const int INF = 0x3f3f3f3f;
 12 const double eps = 1e-6;
 13 const int MAXN = 1e5 + 10;
 14 const int MAXM = 2e6 + 10;
 15 const ll mod = 1e9 + 7;
 16
 17 int f[15][100], dig[15];
 18
 19 void init() {
 20     mst(f, 0);
 21     f[0][0] = 1;
 22     for(int i = 1; i <= 10; i++)
 23         for(int j = 0; j <= i * 9; j++)
 24             for(int k = 0; k <= min(9, j); k++)
 25                 f[i][j] += f[i - 1][j - k];
 26 }
 27
 28 int findall(int pos,int sum,bool limit) {
 29     if(!limit || !pos) return f[pos][sum];
 30     int ans = 0, mx = min(dig[pos], sum);
 31     for(int i = 0; i <= mx; i++)
 32         ans += findall(pos - 1,sum - i,limit && i == dig[pos]);
 33     return ans;
 34 }
 35
 36 int shu[15];
 37
 38 void findd(int pos,int sum,int rnk,bool limit) {
 39     if(!pos) return ;
 40     if(!limit) {
 41         int mx = min(9, sum);
 42         for(int i = 0; i <= mx; i++) {
 43             if(f[pos - 1][sum - i] < rnk) rnk -= f[pos - 1][sum - i];
 44             else {
 45                 shu[pos] = i;
 46                 findd(pos - 1,sum - i,rnk,limit);
 47                 return ;
 48             }
 49         }
 50     } else {
 51         int mx = min(dig[pos], sum);
 52         for(int i = 0; i <= mx; i++) {
 53             int temp = findall(pos - 1,sum - i,i == dig[pos]);
 54             if(temp < rnk) rnk -= temp;
 55             else {
 56                 shu[pos] = i;
 57                 findd(pos - 1,sum - i,rnk,i == dig[pos]);
 58                 return ;
 59             }
 60         }
 61     }
 62 }
 63
 64 int main()
 65 {
 66 #ifdef local
 67     freopen("data.txt", "r", stdin);
 68 //    freopen("data.txt", "w", stdout);
 69 #endif
 70     init();
 71     int n,len = 0;
 72     scanf("%d",&n);
 73     while(n) {
 74         dig[++len] = n % 10;
 75         n /= 10;
 76     }
 77     int ans = 0,sum = 0;
 78     for(int i = 1; i <= len * 9; i++) {
 79         int num = findall(len,i,true);
 80         if(!num) continue;
 81         int l = 1, r = num, num1;
 82         bool flag = false;
 83         while(l <= r) {
 84             int mid = (l + r) >> 1;
 85             findd(len,i,mid,true);
 86             num1 = 0;
 87             for(int j = len; j >= 1; j--) {
 88                 if(!num1 && !shu[j]) continue;
 89                 num1 = num1 * 10 + shu[j];
 90             }
 91             if(sum + mid > num1) l = mid + 1;
 92             else if(sum + mid < num1) r = mid - 1;
 93             else {
 94                 flag = true;
 95                 break;
 96             }
 97         }
 98         if(flag) ans++;
 99         sum += num;
100     }
101     printf("%d\n",ans);
102     return 0;
103 }

原文地址:https://www.cnblogs.com/scaulok/p/9683006.html

时间: 2024-08-04 21:29:16

URAL 2052 Physical Education的相关文章

URAL 2052 Physical Education(数位dp)

 题意:给出一个自然数数列,按照每个数的所有数位之和作为第一关键字,每个数的大小作为第二关键字升序排序,位置不变的数的个数是多少. 思路:首先可以证明,对于数位和为i的所有数,最多只可能有一个位置不变,这个可以直观的猜想一下,因为如果有一个数字位置不变,那么对于排序后的序列,这个数后面的所有数的增长速度都大于自然数序列的增长速度,所以不可能再有第二个. 假设我们当前求出了数位和为i的区间为[l, r],令query(a, b)表示1到a这段区间内数位和为b的数的个数,用su[i-1]表示数位

【CodeForces】915 E. Physical Education Lessons 线段树

[题目]E. Physical Education Lessons [题意]10^9范围的区间覆盖,至多3*10^5次区间询问. [算法]线段树 [题解]每次询问至多增加两段区间,提前括号分段后线段树. #include<cstdio> #include<cctype> #include<set> #include<algorithm> using namespace std; int read(){ char c;int s=0,t=1; while(!i

[Educational Codeforces Round 36]E. Physical Education Lessons

[Educational Codeforces Round 36]E. Physical Education Lessons <题意概括> 给定一个长度为$N\left(1\leqslant N\leqslant10^{9}\right)$的区间 $Q\left(1\leqslant Q\leqslant3\cdot10^{5}\right)$次将区间$\left[L,R\right]$Set为0或1,每次Set后输出区间总和 <做法> $10_{9}$的范围显然不可能是朴素线段树

Codeforces 915 E Physical Education Lessons

题目描述 This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to attend physical education lessons. The end of the term i

CF915E Physical Education Lessons

题意: Alex高中毕业了,他现在是大学新生.虽然他学习编程,但他还是要上体育课,这对他来说完全是一个意外.快要期末了,但是不幸的Alex的体育学分还是零蛋! Alex可不希望被开除,他想知道到期末还有多少天的工作日,这样他就能在这些日子里修体育学分.但是在这里计算工作日可不是件容易的事情: 从现在到学期结束还有 n 天(从 1 到 n 编号),他们一开始都是工作日.接下来学校的工作人员会依次发出 q 个指令,每个指令可以用三个参数 l,r,k 描述: 如果 k=1,那么从 l 到 r (包含端

Physical Education Lessons CodeForces - 915E (动态开点线段树)

Physical Education Lessons CodeForces - 915E This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to attend physical

Educational Codeforces Round 36 (Rated for Div. 2) E. Physical Education Lessons(动态开点线段树)

链接: https://codeforces.com/problemset/problem/915/E 题意: This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to atten

Codeforces 394D Physical Education and Buns 胡搞

题目链接:点击打开链接 题意:给定n个数的序列(能够排序) 操作一次能够使得某个数++或--. 问最少操作几次使得序列变成一个等差序列 输出: 第一行输出最少操作的次数 第二行输出等差数列里的最小项 和 公差的绝对值. 思路:枚举公差,公差范围一定是0到 2Max. 先排个序. 我们使得首项不变.形成一个等差数列. 然后让整个数列位移至 操作后的数组的差值 最小值 == 0.这样这个数列的操作次数= 最大的差值/2. done. #include <iostream> #include <

Physical Education Lessons Codeforces - 915E

http://codeforces.com/problemset/problem/915/E 大概有几种思路: 1.动态开点线段树+标记下传 #1.1标记永久化:想了一会没想出来 1.2可以先扫一遍询问把所有需要的点建出来,然后pushdown就不管没建出来的点了,空间跟标记永久化一样 2.离散化+线段树 3.用splay维护区间(估计没人愿意去写) 4.用一个set<pair<int,int>>记所有非工作日(或工作日)区间,修改就暴力找到相关的区间去改 由于每一次操作最多多出O