算法竞赛入门经典(第2版)-刘汝佳-第八章例题解题源码(C++语言)(部分)

来源:互联网 发布:ubuntu资源监视器 编辑:程序博客网 时间:2024/06/05 06:16

例题8-1

采用直接构造法,也就是经验方法求解,通过猜想感觉经验求解。没有一个通用的模板。

#include<bits/stdc++.h>using namespace std;const int maxn=100;int pancake[maxn],ans[maxn];int len=0,ansi=0;int flip(int index){int tmp[maxn];for(int i=0;i<=index;i++){tmp[i]=pancake[index-i];}for(int i=0;i<=index;i++){pancake[i]=tmp[i];}} void findmaxnumber(int l,int j){int maxnumber=pancake[0],maxindex=0;for(int i=1;i<l;i++){if(maxnumber<pancake[i]){maxnumber=pancake[i];maxindex=i;}}if(maxindex==0){flip(l-1);ans[ansi++]=len-maxindex;ans[ansi++]=j+1;} else{flip(maxindex);ans[ansi++]=len-maxindex;flip(l-1);ans[ansi++]=j+1;}  }bool judge(){int tmp[maxn];memcpy(tmp,pancake,sizeof(pancake));sort(tmp,tmp+len);for(int i=0;i<len;i++){if(pancake[i]!=tmp[i]){return false;}}return true;}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);string s;while(getline(cin,s)){stringstream ss(s);len=0;ansi=0;int in,flag=0;while(ss>>in){if(flag>0)cout<<" ";pancake[len++]=in;cout<<in;flag++;}cout<<endl;for(int i=0;i<len;i++){if(judge()){ans[ansi++]=0;break;}int l=len-i;findmaxnumber(l,i);}for(int i=0;i<ansi-1;i++){cout<<ans[i]<<" ";}cout<<ans[ansi-1]<<endl;}} 

例题8-2

本题目也是采用经验法,进行直接构造。

#include<bits/stdc++.h>using namespace std;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n;while(cin>>n){cout<<"2"<<" "<<n<<" "<<n<<endl;for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(i<26)printf("%c",'A'+i);else{printf("%c",'a'+i-26);}}cout<<endl;}cout<<endl;for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(j<26)printf("%c",'A'+j);else{printf("%c",'a'+j-26);}}cout<<endl;}}return 0;} 

例题8-3

本题最好使用hash,但是一直不能设计好hash函数,使用map会超时,而本题使用的存储方式,一定要将fl声明为全局变量,如果是局部变量会报错,编译器不会提供那么大的空间用于存储。因为有大量的数据读入,所以使用ios::sync_with_stdio(false); 关闭同步,增加速度。

#include<bits/stdc++.h>using namespace std;const int maxn=5000;long long fl[4005*4005];int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);ios::sync_with_stdio(false);long long A[maxn],B[maxn],C[maxn],D[maxn];int m,flag=0;cin>>m;while(m--){if(flag){cout<<endl;}int n;cin>>n;long long ans=0;for(int i=0;i<n;i++){cin>>A[i]>>B[i]>>C[i]>>D[i];}int  r,c,z;long long len=0;for(int i=0;i<n;i++){for(int j=0;j<n;j++){fl[len++]=A[i]+B[j];}}sort(fl,fl+len);for(int i=0;i<n;i++){for(int j=0;j<n;j++){ans+=upper_bound(fl,fl+len,-C[i]-D[j])-lower_bound(fl,fl+len,-C[i]-D[j]);}}cout<<ans<<endl;flag=1;}return 0;}

例题8-4

枚举超时,枚举代码:

#include<bits/stdc++.h>using namespace std;const int maxn=5000+100;int xl[maxn],xr[maxn],yl[maxn],yr[maxn];int visX[maxn],visY[maxn],n;bool dfsx(int *A,int cur){if(cur==n){return true;}for(int i = xl[cur];i<=xr[cur];i++){if(visX[i]) continue;else{visX[i]=1;A[cur]=i;if(dfsx(A,cur+1)) return true;visX[i]=0;}}return false;}bool dfsy(int *A,int cur){if(cur==n){return true;}for(int i = yl[cur];i<=yr[cur];i++){if(visY[i]) continue;else{visY[i]=1;A[cur]=i;if(dfsy(A,cur+1)) return true;visY[i]=0;}}return false;}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);while(cin>>n&&n){memset(visX,0,sizeof(visX));memset(visY,0,sizeof(visY));for(int i=0;i<n;i++){cin>>xl[i]>>yl[i]>>xr[i]>>yr[i];}int X[maxn],Y[maxn];if((!dfsx(X,0))||(!dfsy(Y,0)))cout<<"IMPOSSIBLE"<<endl;else{for(int i=0;i<n;i++){cout<<X[i]<<" "<<Y[i]<<endl;}}}return 0;} 

所以,本题可以采用贪心策略,因为贪心策略的使用,也只是一种猜想,当然在编程前能证明是最好的。本次采用的贪心策略是先将各区间进行按照xr从小到达排序,xr相等的,xl较小的排在前面。排序后的各点在格子区间里面选择尽量小的数作为自己的行数(列数)。目的是让先选择的车,选择的行(列)对后面的车的选择影响最小。

#include<bits/stdc++.h>using namespace std;const int maxn=5000+100;struct rook{int xl,xr,yl,yr;int id;};rook rooks[maxn],rookssort[maxn];bool cmpx(rook a,rook b){if(a.xr!=b.xr)return a.xr<b.xr;    else    return a.xl<b.xl;}bool cmpy(rook a,rook b){if(a.yr!=b.yr)return a.yr<b.yr;    else    return a.yl<b.yl;}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n;while(cin>>n&&n){int ansx[maxn],ansy[maxn],findx=1,findy=1;int visitx[maxn],visity[maxn];memset(visitx,0,sizeof(visitx));memset(visity,0,sizeof(visity));for(int i=0;i<n;i++){rooks[i].id=i;cin>>rooks[i].xl>>rooks[i].yl>>rooks[i].xr>>rooks[i].yr;}sort(rooks,rooks+n,cmpx);for(int i=0;i<n;i++){int flag=0;for(int j=rooks[i].xl;j<=rooks[i].xr;j++){if(!visitx[j]){ansx[rooks[i].id]=j;visitx[j]=1;flag=1;break;}}if(!flag){findx=0;break;}}if(findx){sort(rooks,rooks+n,cmpy);for(int i=0;i<n;i++){int flag=0;for(int j=rooks[i].yl;j<=rooks[i].yr;j++){if(!visity[j]){ansy[rooks[i].id]=j;visity[j]=1;flag=1;break;}}if(!flag){findy=0;break;}}}if(findx&&findy){for(int i=0;i<n;i++){cout<<ansx[i]<<" "<<ansy[i]<<endl;}}elsecout<<"IMPOSSIBLE"<<endl;}return 0;} 

例题8-5

本题目通过等价转换后,代码变的简单。将一个大问题变小。

#include<bits/stdc++.h>using namespace std;int main(){int n;while(cin>>n&&n){long long ans=0,a,last=0;for(int i=0;i<n;i++){cin>>a;ans+=abs(last);last+=a;}cout<<ans<<endl;}return 0;}

例题8-6

本题采用极点扫描法,参考了代码仓库的代码,对关键的扫描部分进行了注释。

// UVa1606 Amphiphilic Carbon Molecules// Rujia Liu// To make life a bit easier, we change each color 1 point into color 0.// Then we only need to find an angle interval with most points. See code for details.#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std;const int maxn = 1000 + 5;struct Point {  int x, y;  double rad; // with respect to current point  bool operator<(const Point &rhs) const {    return rad < rhs.rad;  }}op[maxn], p[maxn];int n, color[maxn];// from O-A to O-B, is it a left turn?bool Left(Point A, Point B) {  return A.x * B.y - A.y * B.x >= 0;}int solve() {  if(n <= 2) return 2;  int ans = 0;  // pivot point  for(int i = 0; i < n; i++) {    int k = 0;    // the list of other point, sorted in increasing order of rad    for(int j = 0; j < n; j++)      if(j != i) {        p[k].x = op[j].x - op[i].x;        p[k].y = op[j].y - op[i].y;        if(color[j]) { p[k].x = -p[k].x; p[k].y = -p[k].y; }        p[k].rad = atan2(p[k].y, p[k].x);        k++;      }    sort(p, p+k);    // sweeping. cnt is the number of points whose rad is between p[L] and p[R]    int L = 0, R = 0, cnt = 2;    while(L < k) {    //注意这个循环体内部cnt不会重置,那么在这个循环中,求解白点的数量,是通过//在相对坐标系中,以原点和p[L]之间的连线作为分割线,以L=0为初始状态,通过扫描的//方法(判断P[R]是否符合要求)计算出左侧白点的数量,当L=1的时候,在L=0时的白点加上符合L=1时分割线的白点,减去//不符合要求的点(实际上只有一个点)。       if(R == L) { R = (R+1)%k; cnt++; }       while(R != L && Left(p[L], p[R])) { R = (R+1)%k; cnt++; } //增加符合要求的点       cnt--;//减去不符合要求的白点。       L++;      ans = max(ans, cnt);    }  }  return ans;}int main() {freopen("datain.txt","r",stdin);  while(scanf("%d", &n) == 1 && n) {    for(int i = 0; i < n; i++)      scanf("%d%d%d", &op[i].x, &op[i].y, &color[i]);    printf("%d\n", solve());  }  return 0;}


例题8-7

本题使用两种方法,进行求解。算法复杂度相同,引入了滑动窗口的概念。

第一种:

#include<bits/stdc++.h>using namespace std;const int maxn = 1000000+5;int A[maxn];int main(){int T,n;scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=0;i<n;i++) scanf("%d",&A[i]);set<int> s;int L=0,R=0,ans=0;while(R<n){while(R<n&&!s.count(A[R])) s.insert(A[R++]);ans = max(ans,R-L);s.erase(A[L++]);}printf("%d\n",ans);}return 0;} 

第二种:滑动窗口

#include<bits/stdc++.h>using namespace std;int A[maxn],last[maxn];map<int,int> cur;int main(){int T,n;scanf("%d",&T);while(T--){scanf("%d",&n);cur.clear();for(int i=0;i<n;i++){scanf("%d",&A[i]);if(!cur.count(A[i])) last[i]=-1;else last[i] = cur[A[i]];//上一个相同元素的下标 。 cur[A[i]] = i;}int L=0,R=0,ans=0;while(R<n){while(R<n&&last[R]<L) R++;//判断是否A[R]元素是否在[L,R]中,如果在就停止。 ans = max(ans,R-L);L++;}printf("%d\n",ans);}return 0;} 

例题8-8

本题基本采用等价转化的思想,并使用set来进行实现。本题列出代码仓库的代码。

// UVa1471 Defense Lines// Rujia Liu// Algorithm 1: use STL set to maintain the candidates.// This is a little bit more intuitive, but less efficient (than algorithm 2)#include<cstdio>#include<set>#include<cassert>using namespace std;const int maxn = 200000 + 5;int n, a[maxn], f[maxn], g[maxn];struct Candidate {int a, g;Candidate(int a, int g):a(a),g(g) {}bool operator < (const Candidate& rhs) const {return a < rhs.a;}};set<Candidate> s;int main() {freopen("datain.txt","r",stdin);int T;scanf("%d", &T);while(T--) {scanf("%d", &n);for(int i = 0; i < n; i++)scanf("%d", &a[i]);if(n == 1) { printf("1\n"); continue; }// g[i] is the length of longest increasing continuous subsequence ending at ig[0] = 1;for(int i = 1; i < n; i++)if(a[i-1] < a[i]) g[i] = g[i-1] + 1;else g[i] = 1;// f[i] is the length of longest increasing continuous subsequence starting from if[n-1] = 1;for(int i = n-2; i >= 0; i--)if(a[i] < a[i+1]) f[i] = f[i+1] + 1;else f[i] = 1;s.clear();s.insert(Candidate(a[0], g[0]));int ans = 1;for(int i = 1; i < n; i++) {Candidate c(a[i], g[i]);set<Candidate>::iterator it = s.lower_bound(c); // first one that is >= cbool keep = true;if(it != s.begin()) {Candidate last = *(--it); // (--it) points to the largest one that is < cint len = f[i] + last.g;ans = max(ans, len);s.insert(c);}if(keep) {s.erase(c); // if c.a is already present, the old g must be <= c.git = s.find(c); // this is a bit cumbersome and slow but it's clearit++;while(it != s.end() && it->a > c.a && it->g <= c.g) s.erase(it++);}}printf("%d\n", ans);}return 0;}

例题8-9

本题目参考书中解答和代码仓库。

// UVa1451 Average// Rujia Liu#include<cstdio>using namespace std;const int maxn = 100000 + 5;int n, L;char s[maxn];int sum[maxn], p[maxn]; // average of i~j is (sum[j]-sum[i-1])/(j-i+1)// compare average of x1~x2 and x3~x4int compare_average(int x1, int x2, int x3, int x4) {  return (sum[x2]-sum[x1-1]) * (x4-x3+1) - (sum[x4]-sum[x3-1]) * (x2-x1+1);}int main() {  int T;  scanf("%d", &T);  while(T--) {    scanf("%d%d%s", &n, &L, s+1);    sum[0] = 0;    for(int i = 1; i <= n; i++) sum[i] = sum[i-1] + s[i] - '0';    int ansL = 1, ansR = L;    // p[i..j) is the sequence of candidate start points    int i = 0, j = 0;    for (int t = L; t <= n; t++) { // end point      while (j-i > 1 && compare_average(p[j-2], t-L, p[j-1], t-L) >= 0) j--; // remove concave points      p[j++] = t-L+1; // new candidate      while (j-i > 1 && compare_average(p[i], t, p[i+1], t) <= 0) i++; // update tangent point      // compare and update solution      int c = compare_average(p[i], t, ansL, ansR);      if (c > 0 || c == 0 && t - p[i] < ansR - ansL) {        ansL = p[i]; ansR = t;      }    }    printf("%d %d\n", ansL, ansR);  }  return 0;}

例题8-10

本题目采用的二分法和贪婪算法结合,通过二分法找到最大值尽量小的那个数,在通过贪心法从右向左尽量搜索,每个子序列在小于找到的那个数的情况,尽量长。这样就能保证S(1)尽量小,满足条件。

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=600;ll m,k,p[maxn],slash[maxn];;bool judge(ll mid,ll& maxnum){for(int i=0;i<k;i++){int j=slash[i]-1;ll sum=p[j];slash[i+1]=j;for(j=j-1;j>=k-i-1;j--){if(i!=k-1){if(sum+p[j]<=mid){sum+=p[j];slash[i+1]=j;}else{break;}}else{sum+=p[j];slash[i+1]=j;}}maxnum=max(maxnum,sum);}if(maxnum<=mid) return true;else return false;}ll bsearch(ll x,ll y){ll mid;slash[0]=m;while(x<y){mid=x+(y-x)/2;ll maxnum=0; if(judge(mid,maxnum)) y=maxnum;else x=mid+1;}return x;}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int T;cin>>T;while(T--){ll lb=0,ub=0,mid,maxnum=0;cin>>m>>k;for(int i=0;i<m;i++){cin>>p[i];ub+=p[i];}mid = bsearch(lb,ub);judge(mid,maxnum);int j=k-1;for (int i=0;i<m-1;i++){if(i==slash[j]&&j>0){cout<<"/"<<" ";j--;}cout<<p[i]<<" ";}if(slash[j]==m-1&&j>0){cout<<"/"<<" ";j--;}cout<<p[m-1]<<endl;}return 0;} 

例题8-11

贪心算法,每次选择最小的两个数进行相加,并将他们的和压入优先队列。

#include<bits/stdc++.h>using namespace std;const int maxn=6000;int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int n;while(cin>>n&&n){int tmp;priority_queue<int, vector<int>,greater<int>> q;for(int i=0;i<n;i++){cin>>tmp;q.push(tmp);}int ans = 0;for(int i=0;i<n-1;i++){int a = q.top();q.pop();int b = q.top();q.pop();ans+=a+b;q.push(a+b);}cout<<ans<<endl;}return 0;} 

习题8-12

我开始并没有使用提供的方法,我们可以发现规律,第k小时第i行。i>2^(k-1)的时候,红气球数量等于第k-1小时第i行的红气球数量,如果i<=2^(k-1)时,红气球数量等于第k-1小时第i行的红气球数量的2倍。这样求出每行再累加起来就可以得到答案。时间复杂度为O(k*(b-a)).经过UVa测试,LTE超时,还是不得不使用书中O(k)的思路。

第一种:TLE

#include<bits/stdc++.h>using namespace std;typedef long long ll;ll cntr(ll k, ll a){if(k==0) return 1;else if(a>(1<<(k-1))) {return cntr(k-1, a-(1<<(k-1)));}else{return cntr(k-1, a)*2;}}int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int T,rnd=1;cin>>T;while(T--){ll k,a,b;ll sum=0;cin>>k>>a>>b;for(ll i=a;i<=b;i++){sum+=cntr(k,i);}cout<<"Case "<<rnd++<<": "<<sum<<endl;}return 0;}

第二种:

通过求解书中的f函数或者g函数都能求解,下面以g函数为例。本题使用了递推。

#include<bits/stdc++.h>using namespace std;long long c(int k)  {      return k == 0 ? 1 : c(k - 1) * 3;  }    long long g(int k, int i)  {      if (i == 0) {          return 0;      }      if (k == 0) {          return 1;      }        int k2 = 1 << (k - 1);     if (i >= k2) {          return 2 * g(k - 1, i - k2) + c(k - 1);      }      else {          return g(k - 1, i);      }  }    int main()  {  //freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);    ios::sync_with_stdio(false);      int T;      cin >> T;      int kase = 0;      while (T--) {          int k, a, b;          cin >> k >> a >> b;          cout << "Case " << ++kase << ": ";           cout << g(k, (1 << k) - a + 1) - g(k, (1 << k) - b) << endl;      }        return 0;  }  

例题8-13

模拟法,主要是要从中挖掘和分析出一些限制条件,避免没有必要的枚举,节省时间。


#include<bits/stdc++.h>using namespace std;typedef long long ll;const ll maxn=100010;int ps[maxn],qs[maxn];int main(){//freopen("datain.txt","r",stdin);//freopen("dataout.txt","w",stdout);int T,rnd=1;cin>>T;while(T--){cout<<"Case "<<rnd++<<": ";ll n;cin>>n;for(ll i=0;i<n;i++) cin>>ps[i];for(ll i=0;i<n;i++) cin>>qs[i];int su=1;for(ll i=0;i<n;)//以i加油站作为起点。 {ll j=i,gas=0,cnt=0,flag=0;while(cnt<n){gas+=ps[j];if(gas>=qs[j]){gas-=qs[j++];if(j == n){j %= n;flag = 1;}//表示已经遍历了N个点,如果能够成功那么cnt==n//如果失败,那么证明以i...n作为起点也不会成功 cnt++;}else{i = j+1;break;}}if(cnt == n){cout<<"Possible from station "<<i+1<<endl;su=0;break;}if(flag){cout<<"Not possible"<<endl;su=0;break;} }if(su)cout<<"Not possible"<<endl;}return 0;}

例题8-14

本题目自己对题意理解不深,使用的是代码仓库的代码,以供参考。

// UVa1607 Gates// Rujia Liu#include<cstdio>#include<algorithm>using namespace std;const int maxm = 200000 + 5;int n, m;struct Gates {  int a, b, o;} gates[maxm];// returns the output of input 000..0111...1 (there are k 0's)int output(int k) {  for(int i = 1; i <= m; i++) {    int a = gates[i].a;    int b = gates[i].b;    int va = a < 0 ? -a > k : gates[a].o;    int vb = b < 0 ? -b > k : gates[b].o;    gates[i].o = !(va && vb);  }  return gates[m].o;}// returns k such that // 1. output(k) = output(n)// 2. output(k-1) = output(0)int solve(int vn) {  int L = 1, R = n;  while(L < R) {    int M = L + (R-L)/2;    if(output(M) == vn) R = M; else L = M+1;  }  return L;}int main() {  int T;  scanf("%d", &T);  while(T--) {    scanf("%d%d", &n, &m);    for (int i = 1; i <= m; i++)      scanf("%d%d", &gates[i].a, &gates[i].b);    int v0 = output(0);    int vn = output(n);    if(v0 == vn) {      for(int i = 1; i <= n; i++) printf("0");    } else {      int x = solve(vn);      for(int i = 1; i < x; i++) printf("0");      printf("x");      for(int i = x+1; i <= n; i++) printf("1");    }    printf("\n");  }  return 0;}

例题8-15

本题通过滑动窗口加枚举的方式,总的而言,主要是枚举那边理解有些困难,其他还好。

代码参考:点击打开链接

#include<iostream> #include<cstring>#include<set>using namespace std;const int N = 1e5 + 5;int s, n, a[N], vis[N];bool flag[N];int ans;void init() {    cin >> s >> n;    int num = 0;    for (int i = 0; i < n; i++) {        cin >> a[i];        if (i < s) {   //对前面的s个进行分析            if (vis[a[i]]) num++;   //统计前s个中重复的数字            vis[a[i]]++;        }    }    for (int i = 0; i < n; i++) {        //如果num=0,说明前s个中没有重复的数字,那么第一个数字可以作为循环的开始        if (num == 0) flag[i] = true;        //窗口开始滑动        if (vis[a[i]] == 2) num--;    //如果此时最左边的数为重复了的数,num需要减1        vis[a[i]]--;        int k = i + s;     //新数字进入滑动窗口        if (k >= n) continue;        if (vis[a[k]]) num++;   //如果已经出现过        vis[a[k]]++;    }}bool judge(int x) {       for (int i = x; i < n; i += s)        if (!flag[i]) return false;    return true;}void solve() {    memset(vis, 0, sizeof(vis));    ans = 0;    for (int i = 0; i < s; i++) {        if (judge(i)) ans++;        if (i >= n) continue;        //从左往右依次遍历,如果当前a[i]前面已经出现过,那么前面必须会有开头,此时必须结束循环        if (vis[a[i]]) break;        vis[a[i]]++;    }}int main() {    //freopen("D:\\txt.txt", "r", stdin);    int t;    cin >> t;    while (t--) {        memset(flag, 0, sizeof(flag));        memset(vis, 0, sizeof(vis));        init();        solve();        cout << ans << endl;    }    return 0;}


例题8-16 

本题目按照书中的方法,没有问题,这里参考了代码仓库的代码,并进行了注释,便于学习。 

#include<cstdio>#include<map>using namespace std;const int maxn = 200000 + 5;int A[maxn], prev[maxn], next[maxn];map<int, int> cur;inline bool unique(int p, int L, int R) {  return prev[p] < L && next[p] > R;  //如果与在p位置的元素相等的前一个元素的位置小于L,后一个元素位置大于R。  //则说明在这个子序列中唯一。 }bool check(int L, int R) {  if(L >= R) return true;  for(int d = 0; L+d <= R-d; d++) {  //从头开始找,尝试第一个元素是不是唯一     if(unique(L+d, L, R))      return check(L, L+d-1) && check(L+d+1, R);      //如果子序列没有唯一元素,返回false     if(L+d == R-d) break;    //从头开始找,尝试最后一个元素是不是唯一     if(unique(R-d, L, R))      return check(R-d+1, R) && check(L, R-d-1);  //如果子序列没有唯一元素,返回false   }  return false;//如果没有唯一元素,返回false. }int main() {//freopen("datain.txt","r",stdin);  int T, n;  scanf("%d", &T);  while(T--) {    scanf("%d", &n);    cur.clear();    for(int i = 0; i < n; i++) {      scanf("%d", &A[i]);      if(!cur.count(A[i])) prev[i] = -1;//如果A[i]没有出现过,则赋值为1.       else prev[i] = cur[A[i]];//如果出现过,则将前一个的索引存入pre。       cur[A[i]] = i;//保存A[i]的索引i。     }    cur.clear();    //同理找到后一个相等元素的位置     for(int i = n-1; i >= 0; i--) {      if(!cur.count(A[i])) next[i] = n;      else next[i] = cur[A[i]];      cur[A[i]] = i;    }    if(check(0, n-1)) printf("non-boring\n");    else printf("boring\n");  }  return 0;}


阅读全文
0 0