[关闭]
@LittleRewriter 2017-10-08T03:19:54.000000Z 字数 3731 阅读 758

D6题解

题解


T1

考虑相邻元素的大小关系,是递增的。
如果相邻的两个不对判一下。
比较糟的是一个大的后面连上一个递增的,特判一下即可。
也可以直接判断删除一个元素之后是否有序

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5. int n;
  6. int a[1000005];
  7. bool check(int pos){//判断删除一个后是否有序
  8. for(int i=1;i<n;i++){
  9. if(i == pos || i+1 == pos) continue;
  10. if(a[i]>a[i+1]) return 0;
  11. }
  12. if(pos >=2 && pos<n&& a[pos-1] > a[pos+1]) return 0;
  13. return 1;
  14. }
  15. int main(){
  16. freopen("sort.in","r",stdin);
  17. freopen("sort.out","w",stdout);
  18. scanf("%d",&n);
  19. for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  20. bool no = 0;
  21. for(int i=1;i<n;i++){
  22. if(a[i]>a[i+1]){
  23. if( check(i) || check(i+1) ){
  24. break;
  25. }else{
  26. no = 1;
  27. break;
  28. }
  29. }
  30. }
  31. if(no) puts("NO");
  32. else puts("YES");
  33. return 0;
  34. }

T2

解同余方程组
30%
用昨天的公式,
60%
用昨天的公式,exgcd求逆元
100%
需要合并

联立,
然后exgcd(a1,-a2,k1,k2)
解出来x,y后解出k1k2使之成立
而这个x就是同时满足上面两个式子的东西
合并之后可以得到 x%(a1a2)=x0
标程:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <cassert>
  5. #include <cmath>
  6. using namespace std;
  7. typedef long long LL;
  8. int a[4],b[4];
  9. LL A,B;
  10. LL gcd(LL a,LL b){
  11. return b==0?a:gcd(b,a%b);
  12. }
  13. LL lcm(LL a,LL b){
  14. return a/gcd(a,b)*b;
  15. }
  16. LL exgcd(LL a,LL b,LL &x,LL &y){
  17. LL t;
  18. if(!b) {x=1;y=0;return a;}
  19. t=exgcd(b,a%b,y,x);
  20. y-=(a/b)*x;
  21. return t;
  22. }
  23. LL mulmod(LL a,LL b,LL p){
  24. LL ret = 0;
  25. while(b){
  26. if(b&1) ret=(ret+a)%p;
  27. b>>=1;
  28. a=(a+a)%p;
  29. }
  30. return ret;
  31. }
  32. void merge(LL a,LL b){
  33. LL k1,k2;
  34. LL g = exgcd(A,-a,k1,k2);
  35. LL M = lcm(A,a);
  36. // assert(abs((B-b)/g*1.*k1)<=1e18);
  37. k1 = mulmod((B-b)/g,k1,M);
  38. // assert(abs(k1*1.*A)<=1e18);
  39. LL x = B-mulmod(k1,A,M);
  40. // printf("# %.3f\n",k1*1.*A);
  41. // assert(x+k1*A == B);
  42. // assert(x+(B-b)/g*k2*a == b);
  43. // printf("# %lld %lld %lld %lld\n",x,k1,A,B);
  44. assert(((x%A)+A)%A == B);
  45. x = ((x%M)+M)%M;
  46. assert(x%A == B);
  47. assert(x%a == b);
  48. A=M;
  49. B=x;
  50. }
  51. int main(){
  52. freopen("mod.in","r",stdin);
  53. freopen("mod.out","w",stdout);
  54. for(int i=0;i<4;i++) scanf("%d%d",&a[i],&b[i]);
  55. A=1,B=0;
  56. for(int i=0;i<4;i++){
  57. merge(a[i],b[i]);
  58. }
  59. // printf("# %lld\n",A);
  60. printf("%lld\n",B);
  61. return 0;
  62. }

顺便推销一波神奇的大数翻倍法

T3

回文串长度是可以二分的。
首先预处理,奇数以某一个字符为中心,偶数以某一个空隙为中心。
本质不同的回文串最多有O(n)个,通过hash记下答案可以求出来包含多少回文串。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <map>
  5. using namespace std;
  6. typedef unsigned long long ULL;
  7. typedef long long LL;
  8. char s[10005];
  9. ULL h[10005],rh[10005],pw[10005];
  10. int L;
  11. ULL hs(int l,int r){
  12. return h[r]-h[l-1]*pw[r-l+1];
  13. }
  14. ULL rhs(int l,int r){
  15. return rh[l] - rh[r+1]*pw[r-l+1];
  16. }
  17. struct N{
  18. int a[26];
  19. bool ok(){
  20. int b[26];
  21. for(int i=0;i<26;i++) b[i]=a[i];
  22. sort(b,b+26);
  23. for(int i=0;i<25;i++){
  24. if(b[i]>0&& b[i] == b[i+1]) return true;
  25. }
  26. return false;
  27. }
  28. void clear(){
  29. memset(a,0,sizeof a);
  30. }
  31. };
  32. LL ans=0;
  33. map<ULL,LL> num;
  34. map<ULL,N> A;
  35. //奇数
  36. void solve_odd(){//二分判断是否出便捷,判断标准为正反读是否一样
  37. for(int i=1;i<=L;i++){
  38. int l = 1,r = min(i,L-i+1)+1;
  39. while(r-l>1){
  40. int mid = (l+r)/2;
  41. if(hs(i-mid+1,i+mid-1)== rhs(i-mid+1,i+mid-1)) l=mid;
  42. else r=mid;
  43. }
  44. int p=l;
  45. int tmp = p;
  46. while(tmp>=1&&num.find(hs(i-tmp+1,i+tmp-1))==num.end()) tmp--;
  47. //两边删直到取出算过的东西为止 ,hash判断
  48. LL sum = 0;
  49. N st;
  50. st.clear();
  51. if(tmp>=1){
  52. sum=num[hs(i-tmp+1,i+tmp-1)];
  53. st = A[hs(i-tmp+1,i+tmp-1)];
  54. }
  55. while(tmp<p){
  56. st.a[s[i+tmp]-'a']+= (tmp == 0?1:2);
  57. if(st.ok()) sum++;
  58. num[hs(i-tmp,i+tmp)] = sum;
  59. A[hs(i-tmp,i+tmp)] = st;
  60. tmp++;
  61. }
  62. ans+=sum;
  63. // printf("# %d %lld\n",i,sum);
  64. }
  65. }
  66. //偶数
  67. void solve_even(){
  68. A.clear();
  69. num.clear();
  70. for(int i=1;i<L;i++){
  71. // printf("### %d\n",i);
  72. int l = 1,r = min(i,L-i)+1;
  73. while(r-l>1){
  74. int mid = (l+r)/2;
  75. if(hs(i-mid+1,i+mid)== rhs(i-mid+1,i+mid)) l=mid;
  76. else r=mid;
  77. }
  78. int p=l;
  79. int tmp = p;
  80. while(tmp>=1&&num.find(hs(i-tmp+1,i+tmp))==num.end()) tmp--;
  81. LL sum = 0;
  82. N st;
  83. st.clear();
  84. // printf("## %d\n",p);
  85. if(tmp>=1){
  86. sum=num[hs(i-tmp+1,i+tmp)];
  87. st = A[hs(i-tmp+1,i+tmp)];
  88. }
  89. while(tmp<p){
  90. // printf("# %d %lld\n",tmp,sum);
  91. st.a[s[i+tmp+1]-'a']+= 2;
  92. if(st.ok()) sum++;
  93. num[hs(i-tmp,i+tmp+1)] = sum;
  94. A[hs(i-tmp,i+tmp+1)] = st;
  95. tmp++;
  96. }
  97. ans+=sum;
  98. // printf("# %d %lld\n",i,sum);
  99. }
  100. }
  101. int main(){
  102. freopen("str.in","r",stdin);
  103. freopen("str.out","w",stdout);
  104. scanf("%s",s+1);
  105. L=strlen(s+1);
  106. s[0]='#';
  107. pw[0]=1;
  108. for(int i=1;i<=L;i++) pw[i] = pw[i-1]*13131 ;
  109. for(int i=1;i<=L;i++) h[i] = h[i-1]*13131 + s[i];//正着求hash
  110. for(int i=L;i>=1;i--) rh[i] = rh[i+1]*13131 + s[i];//反着求
  111. solve_odd();
  112. solve_even();
  113. printf("%lld\n",ans);
  114. fclose(stdout);
  115. return 0;
  116. }

```

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注