sicily 1195. Summation

用一个数组c[i][j]统计第i位,数字j出现的次数

计算数据段[x,y]等价于计算数据段([0,y]-[0,x-1]+m)%m

最高位为s[n-1],1---s[n-1]-1个出现M^n-1次,s[n-1]出现x%M^n-1+1次,其余低位各个位置上的每个数字在该位出现s[n-1]*M^n-2次

其他位类似。。。。从高往低算。

#include<iostream>

#include<cstdio>
#include<cstring>
using namespace std;
const int LEN = 32;
const int M = 16;
unsigned int a[LEN];
unsigned int b[LEN];
void add(unsigned int &x,unsigned int y,int m){
x = (x+y)%m;
}
void solve(unsigned int x,int m,unsigned int *b){
for(int i = 0;i<LEN;++i)b[i] = 0;
if(x==0)return ;
unsigned int c[LEN][M];
unsigned int d[LEN],s[LEN];
int n = 0;
unsigned int tmp = x;
while(tmp>0){
s[n++] = tmp%m;
tmp/=m;
}
d[0] = 1;
for(int i = 1;i<n;i++)d[i] = d[i-1]*m;
memset(c,0,sizeof(c));


for(int i = n-1;i>=0;i--){
for(int j = 0;j<s[i];j++)add(c[i][j],d[i],m);
add(c[i][s[i]],x%d[i]+1,m);
for(int j = i-1;j>=0;j--)
for(int k = 0;k<m;k++)add(c[j][k],s[i]*d[i-1],m);
}
for(int i = n-1;i>=0;i--){
for(int j = 0;j<m;j++)add(b[i],c[i][j]*j,m);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
unsigned int x,y;
memset(a,0,sizeof(a));
while(n--){
scanf("%u%u",&x,&y);
solve(y,m,b);
for(int i = 0;i<LEN;i++)a[i] = (a[i]+b[i])%m;
if(x>0){
solve(x-1,m,b);
for(int i = 0;i<LEN;i++){
a[i] = (a[i]-b[i]+m)%m;
}
}
}
unsigned int ans = 0;
for(int i = LEN-1;i>=0;i--)ans = ans*m+a[i];
printf("%u\n",ans);
}
return 0;
}

你可能感兴趣的:(sicily 1195. Summation)