找回密码
 欢迎注册
楼主: litaoye

[求助] 关于一个运算优化的问题

[复制链接]
 楼主| 发表于 2009-3-20 04:05:19 | 显示全部楼层
我也贴个C#,看看对大家的思路有没有帮助,这道题的平均水平都被大家带高了!
呵呵!
  1.     class Program1318Xor
  2.     {
  3.         class BigIntCompare : IComparer<BigInt>
  4.         {
  5.             public int Compare(BigInt x, BigInt y)
  6.             {
  7.                 for (int i = 3; i >= 0; i--)
  8.                 {
  9.                     if (x.Items[i] > y.Items[i])
  10.                         return 1;
  11.                     else if ((x.Items[i] < y.Items[i]))
  12.                         return -1;
  13.                 }

  14.                 return 0;
  15.             }
  16.         }

  17.         class BigInt
  18.         {
  19.             public uint[] Items;

  20.             public BigInt(string str)
  21.             {
  22.                 string[] item = str.Split(' ');
  23.                 Items = new uint[4];
  24.                 for (int i = 0; i < 4; i++)
  25.                     Items[3 - i] = uint.Parse(item[i]);
  26.             }

  27.             public BigInt()
  28.             {
  29.                 Items = new uint[4];
  30.             }

  31.             public BigInt(uint A)
  32.             {
  33.                 Items = new uint[4];
  34.                 Items[0] = A;
  35.             }

  36.             public bool BitNum(int index)
  37.             {
  38.                 int bit = index >> 5;
  39.                 int current = index - (bit << 5);
  40.                 return ((Items[bit] >> current) & 1) == 1;
  41.             }

  42.             public int FirstIndexOfOne()
  43.             {
  44.                 for (int i = 3; i >= 0; i--)
  45.                 {
  46.                     if (Items[i] == 0)
  47.                         continue;

  48.                     for (int j = 31; j >= 0; j--)
  49.                     {
  50.                         if (((Items[i] >> j) & 1) == 1)
  51.                             return (j + (i << 5));
  52.                     }
  53.                 }

  54.                 return 0;
  55.             }

  56.             public int IndexOfOne(int start)
  57.             {
  58.                 while (start > 0 && !BitNum(start))
  59.                     start--;

  60.                 return start;
  61.             }

  62.             public static BigInt operator *(BigInt A, uint B)
  63.             {
  64.                 BigInt result = new BigInt();
  65.                 ulong mTemp = 0;
  66.                 uint cTemp = 0;

  67.                 for (int i = 0; i < 4; i++)
  68.                 {
  69.                     mTemp = (ulong)A.Items[i] * (ulong)B;
  70.                     result.Items[i] = (uint)(mTemp & 0xFFFFFFFF);
  71.                     result.Items[i] += cTemp;
  72.                     cTemp = (uint)(mTemp >> 32);
  73.                 }

  74.                 if (cTemp != 0)
  75.                     return null;

  76.                 return result;
  77.             }
  78.         }

  79.         private static List<BigInt> AllNumber;
  80.         private static List<int> AllCount;
  81.         private static List<int> AllAccumlation;

  82.         private static List<BigInt> PowerOf10;
  83.         private static int[] PowerOf10Log;

  84.         static void solve()
  85.         {
  86.             preOperation();
  87.             AllNumber = new List<BigInt>();
  88.             AllCount = new List<int>();
  89.             AllAccumlation = new List<int>();

  90.             int N = int.Parse(Console.ReadLine());
  91.             //int N = 100;
  92.             BigInt bInt;

  93.             for (int i = 0; i < N; i++)
  94.             {
  95.                 bInt = new BigInt(Console.ReadLine());
  96.                 //bInt = new BigInt((uint)i);
  97.                 AllNumber.Add(bInt);
  98.             }

  99.             AllNumber.Sort(new BigIntCompare().Compare);
  100.             int hbit = AllNumber[AllNumber.Count - 1].FirstIndexOfOne();
  101.             int position = 0;
  102.             AllCount.Add(1);
  103.             AllAccumlation.Add(0);

  104.             for (int i = 1; i < AllNumber.Count; i++)
  105.             {
  106.                 if (Compare(AllNumber[i], AllNumber[position], hbit) != 0)
  107.                 {
  108.                     position++;
  109.                     AllNumber[position] = AllNumber[i];
  110.                     AllAccumlation.Add(i);
  111.                     AllCount.Add(1);
  112.                 }
  113.                 else
  114.                     AllCount[position]++;
  115.             }

  116.             AllAccumlation.Add(AllNumber.Count);
  117.             AllNumber.RemoveRange(position + 1, AllNumber.Count - position - 1);

  118.             ulong sum = calculateSame(AllNumber.Count - 1, 0, hbit);
  119.             Console.WriteLine(sum << 1);
  120.         }

  121. //计算相同的段
  122.         static ulong calculateSame(int start, int end, int depth)
  123.         {
  124.             if (start == end || PowerOf10Log[depth] == 0)
  125.                 return 0;

  126.             int hBit = AllNumber[start].IndexOfOne(depth);
  127.             int power = PowerOf10Log[hBit];

  128.             if (power == 0)
  129.                 return 0;

  130.             if (start == end + 1)
  131.                 return (ulong)(LogXor(AllNumber[start], AllNumber[end], hBit) * AllCount[start] * AllCount[end]);

  132.             int mid = -1;
  133.             for (int i = start; i >= end; i--)
  134.             {
  135.                 if (!AllNumber[i].BitNum(hBit))
  136.                 {
  137.                     mid = i;
  138.                     break;
  139.                 }
  140.             }

  141.             if (mid == -1)
  142.                 return calculateSame(start, end, hBit - 1);

  143.             ulong sumUpper = calculateSame(start, mid + 1, hBit - 1);
  144.             ulong sumLower = calculateSame(mid, end, hBit - 1);
  145.             ulong sum = sumUpper + sumLower;

  146.             if (power < 0)
  147.                 sum += (ulong)((AllAccumlation[start + 1] - AllAccumlation[mid + 1]) * (AllAccumlation[mid + 1] - AllAccumlation[end]) * power * -1);
  148.             else
  149.                 sum += calculateDiff(start, mid + 1, mid, end, hBit, hBit - 1);

  150.             return sum;
  151.         }

  152. //计算不同的两个段
  153.         static ulong calculateDiff(int startUpper, int endUpper, int startLower, int endLower, int hBit, int depth)
  154.         {
  155.             if (startUpper < endUpper || startLower < endLower)
  156.                 return 0;

  157.             if (startUpper == endUpper && startLower == endLower)
  158.                 return (ulong)(LogXor(AllNumber[startUpper], AllNumber[startLower], hBit) * AllCount[startUpper] * AllCount[startLower]);

  159.             int power = PowerOf10Log[hBit];
  160.             ulong sum = 0;
  161.             int midUpper = endUpper - 1;
  162.             int midLower = endLower - 1;
  163.             bool bit10 = PowerOf10[power].BitNum(depth);

  164.             for (int i = startUpper; i >= endUpper; i--)
  165.             {
  166.                 if (!AllNumber[i].BitNum(depth))
  167.                 {
  168.                     midUpper = i;
  169.                     break;
  170.                 }
  171.             }

  172.             for (int i = startLower; i >= endLower; i--)
  173.             {
  174.                 if (!AllNumber[i].BitNum(depth))
  175.                 {
  176.                     midLower = i;
  177.                     break;
  178.                 }
  179.             }

  180.             if (bit10)
  181.             {
  182.                 //Xor为0的都=power-1
  183.                 sum += (ulong)((AllAccumlation[startUpper + 1] - AllAccumlation[midUpper + 1]) * (AllAccumlation[startLower + 1] - AllAccumlation[midLower + 1]) * (power - 1));
  184.                 sum += (ulong)((AllAccumlation[midUpper + 1] - AllAccumlation[endUpper]) * (AllAccumlation[midLower + 1] - AllAccumlation[endLower]) * (power - 1));
  185.                 sum += calculateDiff(startUpper, midUpper + 1, midLower, endLower, hBit, depth - 1);
  186.                 sum += calculateDiff(midUpper, endUpper, startLower, midLower + 1, hBit, depth - 1);
  187.             }
  188.             else
  189.             {
  190.                 //Xor为1的都=power
  191.                 sum += (ulong)((AllAccumlation[startUpper + 1] - AllAccumlation[midUpper + 1]) * (AllAccumlation[midLower + 1] - AllAccumlation[endLower]) * power);
  192.                 sum += (ulong)((AllAccumlation[midUpper + 1] - AllAccumlation[endUpper]) * (AllAccumlation[startLower + 1] - AllAccumlation[midLower + 1]) * power);
  193.                 sum += calculateDiff(startUpper, midUpper + 1, startLower, midLower + 1, hBit, depth - 1);
  194.                 sum += calculateDiff(midUpper, endUpper, midLower, endLower, hBit, depth - 1);
  195.             }

  196.             return sum;
  197.         }

  198.         static void preOperation()
  199.         {
  200.             PowerOf10 = new List<BigInt>();
  201.             PowerOf10Log = new int[128];

  202.             BigInt bInt = new BigInt(1);
  203.             int hbit;

  204.             while (bInt != null)
  205.             {
  206.                 hbit = bInt.FirstIndexOfOne();
  207.                 PowerOf10Log[hbit] = PowerOf10.Count;
  208.                 PowerOf10.Add(bInt);
  209.                 bInt *= 10;
  210.             }

  211.             int current = 0;

  212.             for (int i = 0; i < PowerOf10Log.Length; i++)
  213.             {
  214.                 if (PowerOf10Log[i] == 0)
  215.                     PowerOf10Log[i] = current * -1;
  216.                 else
  217.                     current = PowerOf10Log[i];
  218.             }
  219.         }

  220.         static int LogXor(BigInt A, BigInt B, int hbit)
  221.         {
  222.             int startbit = hbit >> 5;
  223.             int current = startbit + 1;
  224.             uint firstbit = 0;

  225.             while (firstbit == 0)
  226.             {
  227.                 current--;
  228.                 firstbit = A.Items[current] ^ B.Items[current];
  229.             }

  230.             if (startbit == current)
  231.                 startbit = hbit - (current << 5);
  232.             else
  233.                 startbit = 31;

  234.             for (int i = startbit; i > 0; i--)
  235.             {
  236.                 if (((firstbit >> i) & 1) == 1)
  237.                 {
  238.                     startbit = i;
  239.                     break;
  240.                 }
  241.             }

  242.             hbit = (current << 5) + startbit;

  243.             int power = PowerOf10Log[hbit];

  244.             if (power == 0)
  245.                 return 0;

  246.             if (power < 0)
  247.                 return power * -1;

  248.             if (firstbit > PowerOf10[power].Items[current])
  249.                 return power;

  250.             if (firstbit < PowerOf10[power].Items[current])
  251.                 return power - 1;

  252.             for (int i = current - 1; i >= 0; i--)
  253.             {
  254.                 firstbit = A.Items[i] ^ B.Items[i];
  255.                 if (PowerOf10[power].Items[i] > firstbit)
  256.                     return power - 1;
  257.                 else if (PowerOf10[power].Items[i] < firstbit)
  258.                     return power;
  259.             }

  260.             return power;
  261.         }

  262.         static int Compare(BigInt x, BigInt y, int bit)
  263.         {
  264.             for (int i = bit >> 5; i >= 0; i--)
  265.             {
  266.                 if (x.Items[i] > y.Items[i])
  267.                     return 1;
  268.                 else if (x.Items[i] < y.Items[i])
  269.                     return -1;
  270.             }
  271.             return 0;
  272.         }
  273.     }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-3-20 09:07:25 | 显示全部楼层

回复 151# litaoye 的帖子

( ⊙o⊙ ),都四更了,还在工作。。。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-3-20 09:31:59 | 显示全部楼层
楼主应该注意休息,经常熬夜对身体伤害很大。我现在尽量在12点前睡觉。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-3-20 10:22:33 | 显示全部楼层


宝宝也老熬夜啊?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-3-20 23:29:14 | 显示全部楼层

回复 153# liangbch 的帖子

过了这段时间可能就好了,谢谢提醒!呵呵!
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-3-22 14:59:59 | 显示全部楼层
原帖由 liangbch 于 2009-3-19 10:24 发表
我从0.342优化到0.171,如果优化后速度再提高一倍,就是第一名了。按照楼主的思路,将XOR和log10这2步操作合在一起,用汇编语言写成一个函数,速度应该可以更快。等有时间我将尝试一下。


我现在最好成绩0.078,打破了shshsh_0510的0.093的记录。
1. 先完全汇编语言编写xorLog10,速度提高到0.14秒
2. 然后在计算之前,将至多5000个UINT128 进行了排序,速度不降反增,速度竟提高到0.109.
3.将xorLog10进行调整,减少了指令条数。测试结果为0.093或者0.078

评分

参与人数 2威望 +2 鲜花 +2 收起 理由
litaoye + 1 + 1
shshsh_0510 + 1 + 1 0.078

查看全部评分

毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-3-23 01:07:27 | 显示全部楼层

回复 156# liangbch 的帖子

呵呵,这个成绩c#是无论如何也不可能打破的了!确实很棒!

最近发现这个时间误差有时还是挺大的!
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-3-23 08:33:59 | 显示全部楼层
宝宝的代码我看看

logxor如果用xmm最合适了
log10我的还存在一个跳转无法消

不知你的如何?
[hide=1000000000000000000000000000000000]
   给我elflyao@foxmail.com
[/hide]
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-3-23 08:42:32 | 显示全部楼层
我想C++如果深度汇编优化,打入前三问题不大
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-3-23 09:03:14 | 显示全部楼层

  1. typedef struct
  2. {
  3.     unsigned int d[4];
  4. } UINT128;

  5. unsigned int CompTable[128][2] =  {0,0, 0,0, 0,0, 0,1, 1,0, 1,0, 1,1, 2,0, 2,0, 2,1, 3,0, 3,0, 3,0, 3,1,
  6.     4,0,4,0,4,1,5,0,5,0,5,1,6,0,6,0,6,0,6,1,7,0,7,0,7,1,8,0,8,0,
  7.     8,1,9,0,9,0,9,0,9,1,10,0,10,0,10,1,11,0,11,0,11,1,12,0,12,
  8.     0,12,0,12,1,13,0,13,0,13,1,14,0,14,0,14,1,15,0,15,0,15,0,15,
  9.     1,16,0,16,0,16,1,17,0,17,0,17,1,18,0,18,0,18,0,18,1,19,0,19,
  10.     0,19,1,20,0,20,0,20,1,21,0,21,0,21,0,21,1,22,0,22,0,22,1,23,
  11.     0,23,0,23,1,24,0,24,0,24,0,24,1,25,0,25,0,25,1,26,0,26,0,26,
  12.     1,27,0,27,0,27,0,27,1,28,0,28,0,28,1,29,0,29,0,29,1,30,0,30,
  13.     0,30,1,31,0,31,0,31,0,31,1,32,0,32,0,32,1,33,0,33,0,33,1,34,
  14.     0,34,0,34,0,34,1,35,0,35,0,35,1,36,0,36,0,36,1,37,0,37,0,37,0,37,1,38,0};

  15. UINT128 pow10[40] = {1,0,0,0,
  16.     10,0,0,0,
  17.     100,0,0,0,
  18.     1000,0,0,0,
  19.     10000,0,0,0,
  20.     100000,0,0,0,
  21.     1000000,0,0,0,
  22.     10000000,0,0,0,
  23.     100000000,0,0,0,
  24.     1000000000,0,0,0,
  25.     1410065408,2,0,0,
  26.     1215752192,23,0,0,
  27.     3567587328,232,0,0,
  28.     1316134912,2328,0,0,
  29.     276447232,23283,0,0,
  30.     2764472320,232830,0,0,
  31.     1874919424,2328306,0,0,
  32.     1569325056,23283064,0,0,
  33.     2808348672,232830643,0,0,
  34.     2313682944,2328306436,0,0,
  35.     1661992960,1808227885,5,0,
  36.     3735027712,902409669,54,0,
  37.     2990538752,434162106,542,0,
  38.     4135583744,46653770,5421,0,
  39.     2701131776,466537709,54210,0,
  40.     1241513984,370409800,542101,0,
  41.     3825205248,3704098002,5421010,0,
  42.     3892314112,2681241660,54210108,0,
  43.     268435456,1042612833,542101086,0,
  44.     2684354560,1836193738,1126043566,1,
  45.     1073741824,1182068202,2670501072,12,
  46.     2147483648,3230747430,935206946,126,
  47.     0,2242703233,762134875,1262,
  48.     0,952195850,3326381459,12621,
  49.     0,932023908,3199043520,126217,
  50.     0,730304488,1925664130,1262177,
  51.     0,3008077584,2076772117,12621774,
  52.     0,16004768,3587851993,126217744,
  53.     0,160047680,1518781562,1262177448,
  54.     0, 0, 0, 0};

  55. __declspec(naked)
  56. int __fastcall log_10(UINT128 * n)
  57. {
  58.     __asm
  59.     {
  60.     bsr edx, [ecx]
  61.     bsr eax, [ecx + 4]
  62.     add eax, 32
  63.     cmp [ecx + 4], 0
  64.     cmovne edx, eax
  65.     bsr eax, [ecx + 8]
  66.     add eax, 64
  67.     cmp [ecx + 8], 0
  68.     cmovne edx, eax
  69.     bsr eax, [ecx + 12]
  70.     add eax, 96
  71.     cmp [ecx + 12], 0
  72.     cmovne edx, eax
  73.     mov eax, dword ptr CompTable[8 * edx]
  74.     cmp dword ptr CompTable[8 * edx + 4], 0
  75.     je ex
  76.     add eax, 1
  77.     mov edx, eax
  78.     shl edx, 4
  79.     push ebx
  80.     mov ebx, [ecx]
  81.     sub ebx, pow10[edx]
  82.     mov ebx, [ecx + 4]
  83.     sbb ebx, pow10[edx + 4]
  84.     mov ebx, [ecx + 8]
  85.     sbb ebx, pow10[edx + 8]
  86.     mov ebx, [ecx + 12]
  87.     sbb ebx, pow10[edx + 12]
  88.     sbb ebx, ebx
  89.     add eax, ebx
  90.     pop ebx
  91.   ex:   
  92.     ret
  93.     }   
  94. }
复制代码
log10的汇编版本
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-5 12:37 , Processed in 0.049759 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表