思路:每个位置有0~9共10种可能,而总共有n位,则有10^^n种,再减去不该有的(满足保留号码开头的),而保留号码开头的,由于确定了x位,所以只有10^^(n-x)种,时间复杂度应该是O(n^^2); 个人处理时的难点: 1.采用long long int 记录可能种数,可能不够大,用的数组记录,这样就会涉及数组加减。 2.原本保留号码直接存在包含(不是一般的包含,只是首部开始包含)关系,会导致重复(短的在这里种数是包含了长的那部分),所以先将数据按升序排列,然后从较短数列开始遍历,如果后面有包含这个数列的长数列,则长数列化为‘a’,去重。 #include<bits/stdc++.h> using namespace std; int find(char s1[],char s2[]) { int flag=1; for(int j=0;j<strlen(s1)&&flag;j++) if(s2[j]!=s1[j]) { flag=0; } return flag; }//判断是否包含字串; int len(int a[],int num) { int n=0; for(int i=num-1;i>=0;i--) { if(a[i]>0) { n=i; break; } } return n+1; }//确定int数组的最高位数——————数组表示数需要; int mycmp(int s1[],int s2[],int num) { int flag=0; for(int i=num-1;i>=0&&flag==0;i--) { if(s1[i]>s2[i]) { flag=1; } else if(s1[i]<s2[i]) { flag=-1; } } return flag; }//比较int数组之间的大小————数组表示数需要; int main(void) { int n,m; cin>>n>>m; char limit_num[50][18]; for(int i=0;i<m;i++) { cin>>limit_num[i]; } /*对保留号码数组进行排序*/ for(int i=0;i<m-1;i++) for(int k=m-1;k>i;k--) { if(strcmp(limit_num[k],limit_num[k-1])<0) { char x[18]; strcpy(x,limit_num[k]); strcpy(limit_num[k],limit_num[k-1]); strcpy(limit_num[k-1],x); } } /*去除包含的重复保留号码数组*/ for(int i=0;i<m-1;i++) { if(strcmp(limit_num[i],"a")!=0) for(int k=i+1;k<m;k++) { if(find(limit_num[i],limit_num[k])) strcpy(limit_num[k],"a"); } } /*计算保留号码的种数*/ int minus[50]={0}; for(int i=0;i<m;i++) if(strcmp(limit_num[i],"a")!=0) { minus[n-strlen(limit_num[i])]++; if(minus[n-strlen(limit_num[i])]>=10) { minus[n-strlen(limit_num[i])+1]++; minus[n-strlen(limit_num[i])]-=10; } } /*总数减去保留号码种数*/ int result[50]={0}; result[n]=1; if(mycmp(minus,result,50)>=0) { cout<<0; } else { for(int i=0;i<50;i++) { result[i]-=minus[i]; if(result[i]<0) { result[i]+=10; result[i+1]--; } } int flag=0; for(int i=n;i>=0;i--) { if(result[i]>0&&!flag) { flag=1; cout<<result[i]; } else if(flag) cout<<result[i]; } } return 0; }