给定两个正整数a,b,分别定义两个集合L和R,
集合L:即把1~a,1~b中整数乘积的集合定义为L = {x * y | x,y是整数且1 <= x <=a , 1 <= y <= b};
集合R:1~a,1~b中整数异或的集合定义为集合R = {x ^ y | x,y是整数且1 <= x <=a , 1 <= y <= b},其中^表示异或运算。
现从L中任取一个整数作为A,从R中任取一个整数作为B,如果必要在B的左边补0,使得B达到:“b的位数+1”位(十进制),然后把B接到A的右边,形成的一个十进制数AB。求所有这样形成数的和。
输入a,b 1<=a<=30, 1<=b<=10000000。
输出所有产生的AB数的和,由于结果比较大,输出对1000000007取余数的结果。
例如:a = 2, b = 4,
则L = {1 * 1, 1 * 2, 1 * 3, 1 * 4, 2 * 1, 2 * 2, 2 * 3, 2 * 4} = {1, 2, 3, 4, 6, 8}
R = {1^1,1^2,1^3,1^4,2^1,2^2,2^3,2^4} = {0, 1, 2, 3, 5, 6}
相接的时候保证R中的数至少有两位,所以相接后所有的AB数的集合是
{
100, 101, 102, 103, 105, 106,
200, 201, 202, 203, 205, 206,
300, 301, 302, 303, 305, 306,
400, 401, 402, 403, 405, 406,
600, 601, 602, 603, 605, 606,
800, 801, 802, 803, 805, 806
}
输出它们的和:14502。
题目分析:
这其实算两个题,这么整齐的矩阵实际上主要就是Sum(L)和Sum(R).
求这两个部分都是独立的。所以拆成2个题也没什么问题。
最后的结果result=Sum(L)*Count(R)*Len(p)+Sum(R)*Count(L);
Len(p)简单就是个Pow(10,"b的位数+1")
public static int Len(int b)
{
int len = 100;
while (b/10 > 0)
{
len = len*10;
b = b/10;
}
return len;
}
- 这题一眼看上去,暴力肯定是可以实现的。
var aa = new bool[a*b+1];
var bb = new bool[a + b + 1];
Int64 len = Len(b);
Int64 result1 = 0;
Int64 result2 = 0;
int size1 = 0;
int size2 = 0;
for (int i = 1; i <= a; i++)
{
for (int j = 1; j <= b; j++)
{
if (!aa[i*j])
{
result1 += ((i*j))%MOD;
size1++;
aa[i*j] = true;
}
if (!bb[i ^ j])
{
result2 += (i ^ j)%MOD;
size2++;
bb[i ^ j] = true;
}
}
}
result1 = (result1%MOD)*(len%MOD);
result1 = (result1%MOD)*(size2%MOD);
result2 = (result2%MOD)*(size1%MOD);
return (int) ((result1 + result2)%MOD);
- 优化
private static void DoXor(int a, int b)
{
var bb = new bool[a + b + 1];
if (b <= 31)
{
for (int i = 1; i <= a; i++)
{
for (int j = 1; j <= b; j++)
{
if (!bb[i ^ j])
{
sum2 += (i ^ j)%MOD;
count2++;
bb[i ^ j] = true;
}
}
}
return;
}
int k = b/32 - 1;
int m = (k + 1)*32;
if ((b & 31) == 31)
{
k = k + 1;
m = b + 1;
}
Int64 sum2kk = 0;
Int64 count2kk = 0;
for (int i = 1; i <= a; i++)
{
for (int j = 0; j <= 31; j++)
{
if (!bb[i ^ j])
{
sum2kk += (i ^ j)%MOD;
count2kk++;
bb[i ^ j] = true;
}
}
}
count2 += (count2kk*k);
sum2 += (sum2kk*k)%MOD;
sum2 += count2kk*(k + 1)*k*(32/2)%MOD;
for (int j = m; j <= b; j++)
{
for (int i = 1; i <= a; i++)
{
if (!bb[i ^ j])
{
sum2 += (i ^ j)%MOD;
count2++;
bb[i ^ j] = true;
}
}
}
var kk = new bool[32 + a + 1];
for (int j = 1; j <= 31; j++)
{
for (int i = 1; i <= a; i++)
{
if (!kk[i ^ j])
{
sum2 += (i ^ j)%MOD;
count2++;
kk[i ^ j] = true;
}
}
}
}
private const int MOD = 1000000007;
private static Int64 count1 = 0;
private static Int64 count2 = 0;
private static Int64 sum1 = 0;
private static Int64 sum2 = 0;
public static int Len(int b)
{
int len = 100;
while(b/10>0)
{
len = len*10;
b = b / 10;
}
return len;
}
private static Int64 gcd2(Int64 a, Int64 b)
{
if (b == 0) return a;
return gcd2(b, a % b);
}
private static List<int> ValidNum(int a, int k)
{
List<int> result = new List<int>();
result.Add(k);
bool bFlag = true;
for (int i = k+1; i <= a; i++ )
{
bFlag = true;
foreach (int kk in result)
{
if (i % kk == 0)
{
bFlag = false;
break;
}
}
if (bFlag)
{
result.Add(i);
}
}
return result;
}
private static void CalcSeg(Int64 k, Int64 b, Int64 m, bool add)
{
if (m < k ||m > k*b) return;
Int64 start = ((k - 1) * b + 1) / m + 1;
if (((k-1)*b+1)%m==0)
start = ((k - 1) * b + 1) / m;
Int64 end = k * b / m;
if (add)
{
sum1 += ((start + end) * (end - start + 1) * m / 2) % MOD;
count1 += end - start + 1;
}
else
{
sum1 -= ((start + end) * (end - start + 1) * m / 2) % MOD;
if (sum1 < 0)
sum1 += MOD;
count1 -= end - start + 1;
}
}
public static int run(int a, int b)
{
count1 = count2 = sum1 = sum2 = 0;
bool[] bb = new bool[a + b + 1];
Int64 len = Len(b);
for (int i = 1; i <= a; i++ )
{
List<int> nums = ValidNum(a,i);
int nn = nums.Count;
int[] digit = new int[nn];
int ii,jj;
while (true)//这其实是一个求1-n的全部非空集合的一个模板
{
for (ii = 0; ii < nn && digit[ii] == 1; digit[ii] = 0, ii++) ;
if (ii == nn)
break;
else
digit[ii] = 1;
for (ii = 0; ii < nn && digit[ii] == 0; ii++) ;
int c = 1;
Int64 mul = nums[ii];
for (jj = ii + 1; jj < nn; jj++)
{
if (digit[jj] == 1)
{
mul = (nums[jj] * mul) / gcd2(nums[jj], mul);//太耗时
c++;
}
}
CalcSeg(i, b, mul, c % 2 == 1);
}
}
DoXor(a,b);
sum1 = (sum1 % MOD) * (len % MOD);
sum1 = (sum1 % MOD) * (count2 % MOD);
sum2 = (sum2 % MOD) * (count1 % MOD);
return (int)((sum1 + sum2) % MOD);
}
运行了一下,总算在1秒以下了。但是还是慢,用工具分析了一下,发现计算gcd花费的时间太多了。
private const int MOD = 1000000007;
private static Int64 count1;
private static Int64 count2;
private static Int64 sum1;
private static Int64 sum2;
public static int Len(int b)
{
int len = 100;
while (b/10 > 0)
{
len = len*10;
b = b/10;
}
return len;
}
private static Int64 gcd2(Int64 a, Int64 b)
{
if (b == 0) return a;
return gcd2(b, a%b);
}
private static List<int> ValidNum(int a, int k)
{
var result = new List<int>();
result.Add(k);
bool bFlag = true;
for (int i = k + 1; i <= a; i++)
{
bFlag = true;
foreach (int kk in result)
{
if (i%kk == 0)
{
bFlag = false;
break;
}
}
if (bFlag)
{
result.Add(i);
}
}
return result;
}
private static void CalcSeg(Int64 k, Int64 b, Int64 m, bool add)
{
if (m < k || m > k*b)
{
return;
}
Int64 start = ((k - 1)*b + 1)/m + 1;
if (((k - 1)*b + 1)%m == 0)
start = ((k - 1)*b + 1)/m;
Int64 end = k*b/m;
if (add)
{
sum1 += ((start + end)*(end - start + 1)*m/2)%MOD;
count1 += end - start + 1;
}
else
{
sum1 -= ((start + end)*(end - start + 1)*m/2)%MOD;
if (sum1 < 0)
sum1 += MOD;
count1 -= end - start + 1;
}
}
private static void DoAdd(List<int> nums, int lastkk, Int64 pregcd, int lastn, int n, int i, int b)
{
if (lastn == n)
{
return;
}
for (int m = lastkk + 1; m <= n; m++)
{
Int64 newPregcd = pregcd*nums[m - 1]/gcd2(pregcd, nums[m - 1]);//gcd(a,b,c,d),gcd(a,b,c,e)的时候,pregcd就是gcd(a,b,c),这相当于一个缓存
CalcSeg(i, b, newPregcd, lastn%2 == 0);
DoAdd(nums, m, newPregcd, lastn + 1, n, i, b);//递归
}
}
private static void DoXor(int a, int b)//啰嗦,可以简化一些代码的
{
var bb = new bool[a + b + 1];
if (b <= 31)
{
for (int i = 1; i <= a; i++)
{
for (int j = 1; j <= b; j++)
{
if (!bb[i ^ j])
{
sum2 += (i ^ j)%MOD;
count2++;
bb[i ^ j] = true;
}
}
}
return;
}
int k = b/32 - 1;
int m = (k + 1)*32;
if ((b & 31) == 31)
{
k = k + 1;
m = b + 1;
}
Int64 sum2kk = 0;
Int64 count2kk = 0;
for (int i = 1; i <= a; i++)
{
for (int j = 0; j <= 31; j++)
{
if (!bb[i ^ j])
{
sum2kk += (i ^ j)%MOD;
count2kk++;
bb[i ^ j] = true;
}
}
}
count2 += (count2kk*k);
sum2 += (sum2kk*k)%MOD;
sum2 += count2kk*(k + 1)*k*(32/2)%MOD;
for (int j = m; j <= b; j++)
{
for (int i = 1; i <= a; i++)
{
if (!bb[i ^ j])
{
sum2 += (i ^ j)%MOD;
count2++;
bb[i ^ j] = true;
}
}
}
var kk = new bool[32 + a + 1];
for (int j = 1; j <= 31; j++)
{
for (int i = 1; i <= a; i++)
{
if (!kk[i ^ j])
{
sum2 += (i ^ j)%MOD;
count2++;
kk[i ^ j] = true;
}
}
}
}
public static int run(int a, int b)
{
count1 = count2 = sum1 = sum2 = 0;
var bb = new bool[a + b + 1];
Int64 len = Len(b);
for (int i = 1; i <= a; i++)
{
List<int> nums = ValidNum(a, i);
DoAdd(nums, 0, 1, 0, nums.Count, i, b);
}
DoXor(a, b);
sum1 = (sum1%MOD)*(len%MOD);
Console.WriteLine(sum1 + " " + count1 + " " + sum2 + " " + count2);
sum1 = (sum1%MOD)*(count2%MOD);
sum2 = (sum2%MOD)*(count1%MOD);
return (int) ((sum1 + sum2)%MOD);
}