[关闭]
@sensitive-cs 2017-06-10T15:38:26.000000Z 字数 3658 阅读 741

CQUPT 数论+几何 2017/5/22

题解


poj 2142 the balance
题意:
解不定方程 ax+by = n;|x|+|y|最小,当|x|+|y|相等时,|ax|+|by|最小。
思路:
用扩展欧几里得定理。
设d=gcd(a,b)
则x=x0+b/d*t,y=y0-a/d*t
z=|x|+|y|=|x0+b/d*t|+|y0-a/d*t|
实际上就是求z=|a1*t+c1|+|c2-a2*t|在t取何值时最小。(a2>a1)
首先由不定方程ax+by=c,a>0,b>0,c>0可知,x和y只有下述三种情况:
x>0,y< 0; x< 0,y>0; x>0,y>0;
那么对t分类讨论,得出:
1.t< min(-c< c2/a2,z=(a1-a2)t+c1+c2,单调减
3.t> max(-c1/a1,c2/a2),z=(a1+a2)t+c1-c2,单调增
这样,我们知道当z取最小值时,t=c2/a2=y0/(a/d)=y0*d/a 附近
接着只要在t附近几个比较一下取最小值即可。

代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. using namespace std;
  5. long long mabs(long long a)
  6. {
  7. return a >= 0 ? a : -a;
  8. }
  9. long long exgcd(long long a,long long b,long long &x,long long &y)
  10. {
  11. if (b == 0)
  12. {
  13. x = 1;y = 0;
  14. return a;
  15. }
  16. int r = exgcd(b,a % b,x,y);
  17. int t = x;
  18. x = y;
  19. y = t - a/b*y;
  20. return r;
  21. }
  22. int main()
  23. {
  24. int a,b,c;
  25. while (scanf("%d%d%d",&a,&b,&c) != EOF && a * b *c)
  26. {
  27. bool f = 0;
  28. if (a < b)
  29. {
  30. f = 1;
  31. swap(a,b);
  32. }
  33. long long x0,y0;
  34. long long d;
  35. d = exgcd(a,b,x0,y0);
  36. x0 = x0 * c / d;
  37. y0 = y0 * c / d;
  38. long long z = mabs(x0) + mabs(y0);
  39. long long anx = mabs(x0),any = mabs(y0);
  40. long long t = y0 * d / a;
  41. for (int i = t - 5;i <= t + 5;i++)
  42. {
  43. long long tx = x0 + b / d * i,ty = y0 - a / d * i;
  44. long long tz = mabs(tx) + mabs(ty);
  45. if (tz < z)
  46. {
  47. z = tz;
  48. anx = mabs(tx);
  49. any = mabs(ty);
  50. }
  51. }
  52. if (f)
  53. printf("%I64d %I64d\n",any,anx);
  54. else
  55. printf("%I64d %I64d\n",anx,any);
  56. }
  57. return 0;
  58. }

poj 1830 开关问题
思路:
高斯消元。
求的时自由变量的个数,每个自由变量有0,1两种情况,所以答案是ans << 1。
ma[i][j]表示j灯的状态是否会影响i灯的状态,s是开始状态,e是结束状态,根据异或的可逆性,可以将开始和结束异或,然后求ma矩阵的秩,就是线性代数的那一套。
代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. using namespace std;
  5. int s[35],e[35];
  6. int orz[35];
  7. int ma[35][35];
  8. int mabs(int pp)
  9. {
  10. return pp >= 0 ? pp : -pp;
  11. }
  12. int main()
  13. {
  14. int k;
  15. scanf("%d",&k);
  16. while (k--)
  17. {
  18. memset(s,0,sizeof(s));
  19. memset(e,0,sizeof(e));
  20. memset(ma,0,sizeof(ma));
  21. memset(orz,0,sizeof(orz));
  22. int n;
  23. scanf("%d",&n);
  24. for (int i = 1;i <= n;i++)
  25. scanf("%d",s+i);
  26. for (int i = 1;i <= n;i++)
  27. scanf("%d",e+i);
  28. for (int i = 1;i <= n;i++)
  29. orz[i] = s[i] ^ e[i];
  30. int a,b;
  31. while (scanf("%d%d",&a,&b) == 2)
  32. {
  33. if (!(a*b)) break;
  34. ma[b][a] = 1;
  35. }
  36. for (int i = 1;i <= n;i++) ma[i][i] = 1;
  37. for (int i = 1;i <= n;i++)
  38. ma[i][n+1] = orz[i];
  39. for (int i = 1;i <= n;i++)
  40. {
  41. int t = i;
  42. for (int j = i+1;j <= n;j++)
  43. if (mabs(ma[j][i]) > mabs(ma[t][i])) t = j;
  44. if (t != i)
  45. {
  46. for (int j = 1;j <= n+1;j++) swap(ma[i][j],ma[t][j]);
  47. }
  48. if (ma[t][i] == 0) continue;
  49. for (int j = i + 1;j <= n;j++)
  50. {
  51. if (ma[j][i] == 0) continue;
  52. for (int l = i;l <= n + 1;l++)
  53. ma[j][l] ^= ma[i][l];
  54. }
  55. }
  56. int r1 = 0,r2 = 0;
  57. for (int i = 1;i <= n;i++)
  58. {
  59. bool f1 = 0,f2 = 0;
  60. for (int j = 1;j <= n;j++)
  61. if (ma[i][j]) f1 = 1;
  62. for (int j = 1;j <= n + 1;j++)
  63. if (ma[i][j]) f2 = 1;
  64. if (f1) r1++;
  65. if (f2) r2++;
  66. }
  67. if (r1 == r2 && r1 == n) printf("1\n");
  68. else if (r1 < r2) printf("Oh,it's impossible~!!\n");
  69. else if (r1 == r2) printf("%d\n", 1 << (n - r2));
  70. }
  71. return 0;
  72. }

hdu 5446 unknown treasure
题意:
从n个苹果中选择m个,并且结果对M取余,M是很多个质数的乘积。‘
思路:
首先,求组合数,可以用卢卡斯定理,把对每一个质数取余的结果保存下来,之后用中国剩余定理合并。在中国剩余定理的时候,由于long long会爆炸,所以运用了按位乘的方法。
代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. typedef long long ll;
  4. ll cs[15],ys[15];
  5. ll exgcd(ll a,ll b,ll &x,ll &y)
  6. {
  7. if (b == 0)
  8. {
  9. x = 1;y = 0;
  10. return a;
  11. }
  12. ll r = exgcd(b,a % b,x,y);
  13. ll t = x;
  14. x = y;
  15. y = t - a / b * y;
  16. return r;
  17. }
  18. ll cal(ll a,ll b,ll p)
  19. {
  20. a = (a % p + p) % p;
  21. b = (b % p + p) % p;
  22. ll ans = 0;
  23. for (ll i = 1;i;i <<= 1)
  24. {
  25. //printf(")))))\n");
  26. if (b & i)
  27. ans = (ans + a) % p;
  28. a <<= 1;
  29. a %= p;
  30. }
  31. return ans;
  32. }
  33. ll quick_mod(ll a,ll b,ll p)
  34. {
  35. if (b == 0) return 1;
  36. ll x = quick_mod(a,b / 2,p);
  37. ll ans = x * x % p;
  38. if (b % 2) ans = ans * a % p;
  39. return ans;
  40. }
  41. ll inv(ll a,ll b)
  42. {
  43. ll x,y;
  44. exgcd(a,b,x,y);
  45. return (x % b + b) % b;
  46. }
  47. ll C(ll n,ll m,ll p)
  48. {
  49. if (m > n) return 0;
  50. ll ans = 1;
  51. ll a = 1,b = 1;
  52. for (int i = 1;i <= m;i++)
  53. {
  54. b *= i;
  55. b %= p;
  56. a *= (n - i + 1);
  57. a %= p;
  58. }
  59. return cal(a,inv(b,p),p);
  60. }
  61. ll Lucas(ll n,ll m,ll p)
  62. {
  63. if (m == 0) return 1;
  64. else
  65. return C(n % p,m % p,p) * Lucas(n / p,m / p,p) % p;
  66. }
  67. ll China(int cnt)
  68. {
  69. ll sum = 1;
  70. ll ans = 0;
  71. for (int i = 0;i < cnt;i++)
  72. {
  73. sum *= cs[i];
  74. }
  75. for (int i = 0;i < cnt;i++)
  76. {
  77. ll tt = sum / cs[i];
  78. ll x,y;
  79. exgcd(tt,cs[i],x,y);
  80. ll ans1 = cal(x,ys[i],sum);
  81. ll ans2 = cal(ans1,tt,sum);
  82. ans = (ans2 + ans) % sum;
  83. }
  84. return (ans%sum + sum) % sum;
  85. }
  86. int main()
  87. {
  88. int t;
  89. scanf("%d",&t);
  90. while(t--)
  91. {
  92. memset(cs,0,sizeof(cs));
  93. memset(ys,0,sizeof(ys));
  94. long long n,m;
  95. scanf("%I64d%I64d",&n,&m);
  96. int num;
  97. scanf("%d",&num);
  98. for (int i = 0;i < num;i++)
  99. {
  100. ll tt;
  101. scanf("%I64d",&tt);
  102. cs[i] = tt;
  103. ys[i] = Lucas(n,m,cs[i]);
  104. }
  105. long long ans = China(num);
  106. printf("%I64d\n",ans);
  107. }
  108. return 0;
  109. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注