思路:每个位置有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;
}