清北学堂Day6

Part1--模拟题

今天的题……怎么说呢,我觉得难度比较平均吧。就是第一题没那么简单,第三题没那么难。然后今天拿到了150分。

(1)第一题

这道题呢,其实并不难,但是容易考虑不全。

我的想法:我用last记录上一个保留数的位置(防止前一个被扔掉不能算),然后如果当前的a[i]>last && a[i]>a[i+1],即当前数比两边都大,而且a[i+2]<a[i+1](也就是后面还有递减)的话,就没戏了肯定是NO,否则last就更新为a[i],接着找。

这个想法可以说是非常奇怪了。主要是我第一次写完,觉得程序太简单了,应该不对。然后就找了几组数据,发现——果然不对。所以后面就一直在扣这几组数据:

***************

4

4 4 2 2

***************

5

1 2 5 4 3

***************

6

1 2 5 6 3 7

***************

结果最后还是WA了一个数据,因为没考虑到删除第一个。。所以这题是90分。

我的代码:

 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <algorithm>
 7 using namespace std;
 8 int a[1010101];
 9 int main()
10 {
11     freopen("sort.in","r",stdin);
12     freopen("sort.out","w",stdout);
13     int n;
14     scanf("%d",&n);
15     int cnt=0,last=0;
16     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
17     last=a[1];
18     a[n+1]=9999999;
19     bool ok=true;
20     for(int i=2;i<=n;i++)
21     {
22         if(a[i]>last && a[i]>a[i+1])
23         {
24             if(a[i+1]<=a[i+2]) {cnt++;last=a[i];i++;}
25             else cnt++;
26         }
27         else if(a[i]<last) cnt++;
28         else if(a[i]>=last) last=a[i];
29         //cout<<i<<" "<<last<<" "<<cnt<<endl;
30         if(cnt>1) {ok=false;break;}
31     }
32     printf(ok==true? "YES":"NO");
33     //system("pause");
34     return 0;
35 }
36 /*
37 4
38 4 4 2 2
39 */
sort

但是其实这种分情况讨论的思路风险挺大的,考试的时候很有可能有些点就是考虑不到。(比如去年普及组第二题……唉真是不想多说了)所以能不用就不用。这道题比较简单的正解是:求最长不下降子序列,如果这个长度>=n-1,就输出YES;否则NO。这个确实是很本质。

然而标程用的也不是最长不下降子序列...标程考虑相邻两个的大小关系。

若a[i]>a[i+1],则考虑删掉其中一个,能否变为有序

标程:

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

(2)第二题

我觉得老师出这道题纯粹就是想巩固一下昨天讲的内容吧……然而中国剩余定理太难了……所以就暴力枚举了一波。老师说枚举只能拿30,也不知道怎么拿到了60。再次证明数据比较水。。

我的代码:

 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <algorithm>
 7 using namespace std;
 8 
 9 int main()
10 {
11     freopen("mod.in","r",stdin);
12     freopen("mod.out","w",stdout);
13     int a1,b1,a2,b2,a3,b3,a4,b4;
14     scanf("%d%d%d%d%d%d%d%d",&a1,&b1,&a2,&b2,&a3,&b3,&a4,&b4);
15     long long x=1;
16     bool ok=false;
17     while(!ok)
18     {
19         if(x%a1==b1 && x%a2==b2 && x%a3==b3 && x%a4==b4) ok=true;
20         else x++;
21     }
22     printf("%d",x);
23     //system("pause");
24     return 0;
25 }
mod

老师的标程用的就是exgcd了。

标程:

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

(3)第三题

这道题……非常奇怪,一分都没得到。不知道是哪里出了问题。这道题还是暴力,都搜一遍。

我的代码:

 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <algorithm>
 7 using namespace std;
 8 int l;
 9 int minn,maxn;
10 char s[1010];
11 int m[30];
12 bool judge(int x,int y)
13 {
14     bool ok=true;
15     while(x<=y)
16     {
17         x++;y--;
18         if(s[x]!=s[y]) {ok=false;break;}
19     }
20     return ok==true? true:false;
21 }
22 void find(int x,int y)
23 {
24     for(int i=x;i<=y;i++)
25     {
26         m[s[i]-'a'+1]++;
27         if(s[i]-'a'+1>maxn) maxn=s[i]-'a'+1;
28         if(s[i]-'a'+1<minn) minn=s[i]-'a'+1;
29     }
30 }
31 bool ok()
32 {
33     for(int i=minn;i<=maxn;i++)
34         if(m[i]==m[i-1]) return true;
35     return false;
36 }
37 
38 int main()
39 {
40     freopen("str.in","r",stdin);
41     freopen("str.out","w",stdout);
42     cin>>s;
43     l=strlen(s);
44     int ans=0;
45     
46     for(int i=0;i<l;i++)
47     {
48         for(int j=i+3;j<l;j++)
49         {
50             if(s[i]!=s[j]) continue;
51             else
52             {
53                 memset(m,0,sizeof(m));
54                 minn=9999;maxn=0;
55                 if(judge(i,j))
56                 {
57                     find(i,j);
58                     sort(m+minn,m+maxn+1);
59                     if(ok()) ans++;
60                 }
61             }
62         }
63     }
64     printf("%d",ans);
65     //system("pause");
66     return 0;
67 }
str

标程就比较复杂了,有用到hash。看来这道题想拿满还是不容易的

标程:

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

Part2--字符串专题

  • 常用:Hash,KMP,Manacher,exKMP,Trie树,AC自动机(Trie图)
  • (1)Hash(哈希):一个字符串到整数的映射

用处:快速比较两个字符串是否相等      只需O(n)

*Hash相等字符串大概率相等,Hash不等字符串一定不等

实现:RK-hash:把一个字符串看作一个base进制的大整数,然后对一个素数P取模

hash[i]=(hash[i-1]*base+s[i])%p;

【e.g】:1234500000000%p

             ↑

    (1*10+2)%p

     (12*10+3)%p

            .......

【Q】:如何求任意一段hash值?

hash[l-1]*pow(base,r-l+1)      【注】:pow(x,y)=x的y次方

【Q】:求2字符串的最大公共前缀(LCP):用二分来求

【Q】:判断两字符串的大小(字典序)

************************************************************

几个哈希需要注意的问题:

  1. base要>26,不然字母存不下
  2. 字母不要映射为0

             abcd != bcd

            0123 --> 123

3.p一定是long long范围内的素数

如:10^18+9,23333333333333333(16个3)

************************************************************

  • KMP:单模式串匹配

代码实现如下:

 1 //KMP  poj2752 
 2 char t[] //模式串
 3 int j=0;
 4 for(int i=1;i<=n;i++)
 5 {
 6     while(j /*如果失配*/&& t[i]!=s[j+1]) j=nxt[j]; //尝试更短的串 
 7     if(y[i]==s[j+1]) j++;
 8     if(j==m)  //整串匹配完毕 
 9     {
10         j=nxt[j];
11     }
12 } 
  • Manacher求最长子串

//求最长子串
//1:暴力O(n^2)
for(int i=1;i<=L;i++)
{
    r[i]=1;
    whlie(s[i-r[i]]==s[i+r[i]]) r[i]++;  //r[i]记录以i为中心最长能扩展出的回文串 
}
//2:Manacher  O(n)
//利用对称性,即通过已查找出的回文串(关于i对称,i+r[i]是右界)来判断当前(id为中心)是否为回文串 (将id对称到i左边) 
int mx=max(i+r[i]-1);
int id;  //mx取到最大值时的i
for(int i=1;i<=L;i++)
{
    r[i]=min(r[id-(i-id)],mx-1);  //保证未出界
    while(s[i-r[i]]==s[i+r[i]]) r[i]++;
    if(i+r[i]-1>mx)
    {
        mx=i+r[i]-1;
        id=i;
    } 
}
  • 扩展KMP:
 1 //扩展KMP(EXKMP),思路和manacher一样  tyvj-->1068
 2 //1:暴力
 3 for(int i=1;i<=n;i++)
 4 {
 5     p[i]=0;
 6     while(b[i+p[i]]==b[p[i]+1]/*b串*/) p[i]++;
 7 }
 8 //2:
 9 for(int i=1;i<=n;i++)
10 {
11     p[i]=min(mx-i,p[i-id]);
12     while(b[i+p[i]]==b[p[i]+1]) p[i]++;
13     if(i+p[i]>mx)
14     {
15         id=i;
16         mx=i+p[i];
17     }
18 }
  • Trie树
 1 //Trie树:字符串排序    例题:poj2001 3630 3764(XOR最大) 
 2 int trie[100000][26];
 3 int tot;
 4 //root=0;
 5 
 6 void insert(char*s)
 7 {
 8     int p=0;
 9     for(int i=0;s[i];i++)
10     {
11         if(trie[p][s[i]-'a']) id=trie[p][s[i]-'a'];
12         else id=trie[p][s[i]-'a']=++tot;
13     }
14     flag[p]++;
15 }
  • AC自动机(也称Trie图):

AC自动机:把Trie树上不存在的孩子用它fail节点的孩子补出来
fail节点的概念与KMP的next类似
可以用一次bfs来求出

*这个就比较难了,noip的话不掌握也没关系*

 

转载于:https://www.cnblogs.com/lulala/p/7632834.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值