[关闭]
@ysner 2018-07-22T10:30:18.000000Z 字数 4019 阅读 1819

[NOI2018]屠龙勇士

数论


题面

咕咕咕,直接概括题意就没意思了,戳我

解析

一是明确了用哪把剑刺恐龙,而且意味着只要把血量打到及以下即可。
取刺杀每只恐龙的最大时间。
注意无条件向上取整。(可以用,也可以)

  1. il void solve1()
  2. {
  3. re ll now=atk[1],mn=-1e18;
  4. fp(i,1,n)
  5. {
  6. mn=max(mn,ceil(1.0*a[i]/now));
  7. now=b[i];
  8. }
  9. printf("%lld\n",mn);
  10. }

就要预处理用哪个剑刺一条龙的了。
对我这种不太会用的蒟蒻还是很良心的,可以二分出是哪个剑,还可以用插入排序来加入或删除数。
预处理复杂度直达

注意到这一档数据有个独特性质:
手玩了几组数据,发现一定比小。
于是直接爆枚 刺龙次数 到
什么,你怕?怕爆炸?

  1. il int find(re int x)
  2. {
  3. re int l=1,r=m,ans=1;
  4. while(l<=r)
  5. {
  6. re int mid=l+r>>1;
  7. if(atk[mid]<=x) ans=mid,l=mid+1;
  8. else r=mid-1;
  9. }
  10. return ans;
  11. }
  12. il void solve3()
  13. {
  14. fp(i,1,n)
  15. {
  16. re int x=find(a[i]);
  17. ying[i]=atk[x];
  18. fp(j,x,m-1) atk[j]=atk[j+1];
  19. re int ppl=find1(b[i]);
  20. fq(j,m,ppl+1) atk[j]=atk[j-1];
  21. atk[ppl]=b[i];
  22. }
  23. re ll mn=-1e18;
  24. fp(i,1,n) mn=max(mn,(ceil(1.0*a[i]/ying[i])));
  25. fp(i,mn,1000000)
  26. {
  27. re int ppl=1;
  28. fp(j,1,n) if((i*ying[j]-a[j])%p[j]!=0) {ppl=0;break;}
  29. if(ppl) {printf("%d\n",i);return;}
  30. }
  31. puts("-1");
  32. }

意思是只要我们在不暴枚的前提下解一个方程
有模号?化成同余方程形式
这种方程解不得,继续化。

然后发现了性质的用途。。。

这就是同余方程的经典模型,不记得就去看专项总结关于同余方程解法

  1. il void exgcd(re ll A,re ll B,re ll &D,re ll &x,re ll &y,re ll c)
  2. {
  3. if(!B) x=1,y=0,D=A;
  4. else exgcd(B,ok(A,B),D,y,x,c),y-=(A/B)*x;
  5. }
  6. il void solve2()
  7. {
  8. re ll A=atk[1],B=a[1],M=p[1],D,x,y,ysn,zsy;
  9. exgcd(A,M,D,x,y,B);
  10. if(B%D) {puts("-1");return;}
  11. ysn=B/D,zsy=M/D;
  12. x=ok((ok(x*ysn,zsy)+zsy),zsy);
  13. //x=ok(x,zsy);
  14. printf("%lld\n",x);
  15. }

又不要解方程了。
这档数据专门卡逗逼的预处理。

它要求一种数据结构,能二分查找,能删除,能插数,能自动排序。
然后我想起来了平衡树。。。

神器了解一下,有了它,这一档根本就没多少码量。

  1. il void solve4()
  2. {
  3. s.clear();
  4. fp(i,1,m) s.insert(atk[i]);
  5. fp(i,1,n)
  6. {
  7. it=s.lower_bound(a[i]);
  8. if(it!=s.begin()) --it;
  9. ying[i]=*it;
  10. s.erase(it);s.insert(b[i]);
  11. }
  12. re ll mn=-1e18;
  13. fp(i,1,n) mn=max(mn,ceil(1.0*a[i]/ying[i]));
  14. printf("%lld\n",mn);
  15. }

算法

拓展中国剩余定理专门用来解多个同余方程。
而这题好像是个板子。
还是专项总结关于同余方程解法
然而我犯了个细节错误:

  1. il ll mul(re ll x,re ll y,re ll mod)
  2. {
  3. if(y<0)x=-x,y=-y;//!!!!!!
  4. re ll S=0,n=y,T=x;
  5. while(n)
  6. {
  7. if(n&1) (S+=T)%=mod;
  8. (T+=T)%=mod;
  9. n>>=1;
  10. }
  11. return S;
  12. }
  1. il ll ok(re ll x,re ll y){while(x<0) x+=y;while(x>=y) x-=y;return x;}
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<set>
  8. #define re register
  9. #define il inline
  10. #define ll long long
  11. #define max(a,b) ((a)>(b)?(a):(b))
  12. #define min(a,b) ((a)<(b)?(a):(b))
  13. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  14. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  15. using namespace std;
  16. const int N=2e5+100;
  17. int T;
  18. ll n,m,a[N],p[N],b[N],atk[N],ying[N],ysn[N];
  19. multiset<ll>s;
  20. multiset<ll>::iterator it;
  21. il ll gi()
  22. {
  23. re ll x=0,t=1;
  24. re char ch=getchar();
  25. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  26. if(ch=='-') t=-1,ch=getchar();
  27. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  28. return x*t;
  29. }
  30. il void wri(re ll x)
  31. {
  32. if(x<0) putchar('-'),x=-x;
  33. if(x>9) wri(x/10);
  34. putchar(x%10+48);
  35. }
  36. il void exgcd(re ll A,re ll B,re ll &D,re ll &x,re ll &y)
  37. {
  38. if(!B) x=1,y=0,D=A;
  39. else exgcd(B,A%B,D,y,x),y-=(A/B)*x;
  40. }
  41. il ll gcd(re ll x,re ll y){if(x<y) swap(x,y);if(!y) return x;else return gcd(y,x%y);}
  42. il ll lcm(re ll x,re ll y){return x/gcd(x,y)*y;}//!!!!!!
  43. il ll mul(re ll x,re ll y,re ll mod)
  44. {
  45. if(y<0)x=-x,y=-y;//!!!!!!
  46. re ll S=0,n=y,T=x;
  47. while(n)
  48. {
  49. if(n&1) (S+=T)%=mod;
  50. (T+=T)%=mod;
  51. n>>=1;
  52. }
  53. return S;
  54. }
  55. il void solve()
  56. {
  57. s.clear();
  58. fp(i,1,m) s.insert(atk[i]);
  59. fp(i,1,n)
  60. {
  61. it=s.lower_bound(a[i]+1);
  62. if(it!=s.begin()) --it;
  63. ying[i]=*it;
  64. s.erase(it);s.insert(b[i]);
  65. }
  66. fp(i,1,n)
  67. {
  68. re ll A=ying[i],B=a[i],M=p[i],D,x,y;
  69. exgcd(A,M,D,x,y);
  70. if(B%D) {puts("-1");return;}
  71. x=mul(x,B/D,M/D);
  72. ysn[i]=x;p[i]/=D;
  73. }
  74. fp(i,2,n)
  75. {
  76. re ll A=p[i-1],B=ysn[i]-ysn[i-1],M=p[i],D,x,y;
  77. re ll L=lcm(p[i-1],p[i]);
  78. exgcd(A,M,D,x,y);
  79. if(B%D){puts("-1");return;}//!!!!!!
  80. x=mul(B/D,x,L);
  81. ysn[i]=ysn[i-1]+mul(x,p[i-1],L);//!!!!!!
  82. ysn[i]=(ysn[i]%L+L)%L;
  83. p[i]=L;
  84. }
  85. re ll ans=ysn[n];
  86. fp(i,1,n) if(ans*ying[i]<a[i]) ans+=(((a[i]-ans*ying[i]+ying[i]-1)/ying[i]+p[n]-1)/p[n]*p[n]);
  87. wri(ans);putchar('\n');
  88. }
  89. int main()
  90. {
  91. T=gi();
  92. while(T--)
  93. {
  94. n=gi();m=gi();
  95. fp(i,1,n) a[i]=gi();fp(i,1,n) p[i]=gi();
  96. fp(i,1,n) b[i]=gi();fp(i,1,m) atk[i]=gi();sort(atk+1,atk+1+m);
  97. solve();
  98. }
  99. return 0;
  100. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注