Codeforces#572 Div2 C---Candies!【倍增】【DP】【思维】
题目:http://codeforces.com/contest/1189/problem/C
题意:给定n个数,每次查询一个区间$[l,r]$。对这个区间内的数,相邻两个数之和超过10,则得到一个candy,然后将他们之和取模10的结果作为新的数。
一共操作$l-r$次,问这个区间得到的candy数。
思路:一种思路是可以发现,实际上candy数是和/10,而新得到的数实际上是/10之后的小数部分。
每次操作的过程其实可以看成是两两求和然后取/10的整数部分,然后把小数部分再两两求和取整数部分,剩下的再留给下一次操作。
所以$ans[l,r] = \lfloor \frac{a_l+a_{l+1}+...+a_r}{10} \rfloor$
另一种思路是用倍增的思想进行dp。
$dp[i][k]$表示以$i$为开头,$2^k$个数所得到的candy数。因为转移的时候还需要知道当前操作之后的数是什么,所以用$dig[i][k]$记录对应操作后的数。
$dp[i][k] = dp[i][k-1]+dp[i + 2^{k-1}][k-1] +(dig[i][k-1] + dig[i + 2^{k-1}][k-1] \ge 10)$
DP解法
1 #include<cstdio> 2 #include<cstdlib> 3 #include<map> 4 #include<set> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<cmath> 9 #include<stack> 10 #include<queue> 11 #include<iostream> 12 13 #define inf 0x3f3f3f3f 14 using namespace std; 15 typedef long long LL; 16 typedef pair<int, int> pr; 17 18 const int maxn = 1e5 + 5; 19 int n, q; 20 int num[maxn]; 21 int dp[maxn][20], dig[maxn][20]; 22 23 int main() 24 { 25 scanf("%d", &n); 26 for(int i = 1; i <= n; i++){ 27 scanf("%d", &num[i]); 28 dp[i][0] = 0; 29 dig[i][0] = num[i]; 30 } 31 int pow = 2; 32 for(int k = 1; k < 20; k++, pow *= 2){ 33 for(int i = 1; i + pow <= n + 1; i++){ 34 dp[i][k] = dp[i][k - 1] + dp[i + pow / 2][k - 1]; 35 if(dig[i][k - 1] + dig[i + pow / 2][k - 1] >= 10)dp[i][k]++; 36 dig[i][k] = (dig[i][k - 1] + dig[i + pow / 2][k - 1]) % 10; 37 } 38 } 39 scanf("%d", &q); 40 while(q--){ 41 int l, r; 42 scanf("%d%d", &l, &r); 43 int k = 0, seg = r - l + 1; 44 while(seg % 2 == 0){ 45 k++; 46 seg >>= 1; 47 } 48 printf("%d\n", dp[l][k]); 49 } 50 return 0; 51 }
公式解法:
#include<cstdio> #include<cstdlib> #include<map> #include<set> #include<cstring> #include<algorithm> #include<vector> #include<cmath> #include<stack> #include<queue> #include<iostream> #define inf 0x3f3f3f3f using namespace std; typedef long long LL; typedef pair<int, int> pr; const int maxn = 1e5 + 5; int n, q; int num[maxn], sum[maxn]; int main() { scanf("%d", &n); for(int i = 1; i <= n; i++){ scanf("%d", &num[i]); sum[i] = sum[i - 1] + num[i]; } scanf("%d", &q); while(q--){ int l, r; scanf("%d%d", &l, &r); printf("%d\n", (sum[r] - sum[l - 1]) / 10); } return 0; }