2021.4.10月赛题解

2021.4.10月赛题解

    • A -火柴棒不等式
    • B-内卷
    • C-放在哪儿好呢?
    • D-山不平何以平天下
    • E-排行统计
    • F-买花
    • G-Race
    • H-最小互质数
    • J-上进的LZ
    • K-填数

A -火柴棒不等式

题:
给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?
等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。
用火柴棍拼数字0-9的拼法如图所示:
在这里插入图片描述
注意:
加号与等号各自需要两根火柴棍
如果A≠B 则A+B=C与B+A=C视为不同的等式(A,B,C>=0)
n根火柴棍必须全部用上
输入
一个正整数n, 1<=n<=24
输出
一个整数,能拼成的不同等式的数目

样例输入:
18
样例输出:
9

ps:本来以为是道益智题,没想到是简单暴力emmmmm。

思路:
首先用一个数组去存储十个数字所需要用的火柴棒数。
由题知n最大为24,数字一是用的最少火柴棒数为二,2 * 4 * 3 + 4 = 24 。
所以可知加数和被加数最大不会超过1000,然后双for循环暴力可解。

注意:
0 + 0 = 0 的情况也要考虑,这是可行的 。

#include
using namespace std ;

int main()
{
	int n ;
	cin >> n ;
	
	int a[15] = { 6 , 2 , 5 , 5 , 4 , 5 , 6 , 3 , 7 , 6 } ;
	n -= 4 ;
	int i , j ,sum = 0 , flag = 0 ;
	for( i = 0 ; i < 1000 ; ++i )
	{
		
		int m = i , s = 0 ;
		if( i == 0 )
		{
			s = 6 ;
		}
		while( m )
		{
			s += a[ m % 10 ] ;
			m /= 10 ;
			
		}
		for( j = 0 ; j < 1000 ; ++j )
		{
			
			int k = j , ss = 0 ;
			if( j == 0 )
			{
				ss = 6 ;
			}
			while( k )
			{
				ss += a[ k % 10 ] ;
				k /= 10 ;
			}
			int kk = i + j , sss = 0 ;
			if( kk == 0 )
			{
				sss = 6 ;
			}
			while( kk )
			{
				sss += a[ kk % 10 ] ;
				kk /= 10 ;
			}
			if( s + ss + sss == n )
				sum++ ;
		}
	}
	cout << sum  << endl ;
	return 0 ;
}

B-内卷


期末有n个同学写论文,第i个人写论文的字数在 [ Li , Ri ] 之间,定义wi为某个同学写的字数。
所以Li≤wi≤Ri
而成绩的得分是非常有趣的,第i个同学gi的论文得分为n-Ki
Ki是比当前这个人的论文字数多的人数
每个人都想写尽可能多的字,因为每位同学都想尽可能得到更高的得分。
所以很容易想到让wi=Ri即可。
但是zks发现了有一个有趣的现象
假设对于每位同学来说,∀i∈[1,n] Li=1000,Ri=10000. 那么在最积极情况下,每位同学都写10000字,即wi=10000.
所以每位同学的得分都为n-0(ki=0,因为没有被任何同学超过)。但是如果每位同学都写1000字,每个人的得分仍然为n-0.
这种现象被称之为内卷
感受到内卷的威力了嘛?!
现在让你尽可能降低1~n位同学所有字数总和的情况下,即min{w1+w2+…+wn} 的同时保证每位同学不能低于在尽自己最大努力时所能得到的分数
你能帮帮zks解决这个问题吗?

输入
第一行有一个正整数n
接下来有n行,第i行有两个正整数Li,Ri
1≤n≤1e5
1≤Li≤Ri≤1e9
输出
输出最小的 w1+w2+…+wn的值

样例输入
3
1 10000
1 10000
1 10000
样例输出
3

提示
样例2:
输入
4
1 2
2 2
2 4
3 4
输出
10

思路:
自定义一个cmp结构体排序,优先利用最大字数从小到大排出名次,其次若名次相同则从大到小排最小字数。
若名次高者所取最小字数比后一名小,则使二者为并列,可达到字数最小学生得到最大努力分数的目的 。
注意:如果排完是并列名次,还需要取并列学生中最小字数的最大值 , 可达到字数最少得分不变的目的 。

#include
#include
using namespace std ;

struct nj
{
	long a , b ;
}p[100005] ;

bool cmp ( nj x , nj y )
{
	if( x.b == y.b )
		return x.a > y.a ;
	else
		return x.b < y.b ;
}

int main()
{
	int n , i , j ;
	cin >> n ;
	p[0].a = p[0].b = 0 ;
	p[n+1].a = p[n+1].b = 0 ;
	int mm ;
	long long sum = 0 ;
	for( i = 1 ; i <= n ; ++i )
		cin >> p[i].a >> p[i].b ;
	sort( p+1 , p+1+n , cmp ) ;
	
	int f = 0 ;
	for( i = 1 ; i <= n ; ++i )
	{
		if( p[i].b != p[i-1].b && p[i].b != p[i+1].b  )
		{
			if( p[i].a <= f )
			{
				sum += f ;
			}
			else
			{
				f = p[i].a ;
				sum += f ;
			}
		}
		else
		{
			if( p[i].b != p[i-1].b )
			{ 
				mm = p[i].a ;
				if( mm < f && f )
					mm = f ;
				sum += mm ;
				f = mm ;
			}
			else
			{
				sum += mm ;
			}
		}
	}
	
	cout << sum << endl ;
	return 0 ;
 } 

C-放在哪儿好呢?


zks正在和mqj玩一个数字游戏,游戏规则如下
zks在水平数轴上放置了n个正整数,第i个数为ai
mqj放置了m个正整数,第j个数为bj
现在由瑶姐在水平数轴上任意位置放置一个实数c
如果存在一个ai ( 1≤i≤n) ,对所有bj (1≤j≤m)来说,都满足| c-ai |<| c-bj |时,那么zks将获得一分。
而瑶姐希望zks分数尽可能高,所以实数c的放置位置就至关重要。
如果zks得分为0,输出Impossible
请你帮瑶姐计算zks最高得分为多少

输入
有多组测试数据
第一行为两个正整数n,m (1≤n,m≤1e5)
第二行为n个正整数a1,a2…an
第三行为m个正整数b1,b2…bm
1≤ai,bi≤1e9
输出
输出zks最高的得分,如果为无法得分,则输出Impossible

样例输入
2 2
2 3
1 4
6 5
2 5 3 7 1 7
3 4 3 1 10
1 1
7
7
样例输出
2
3
Impossible

提示
第一个例子:当c=2.5时,zks将得2分
第二个例子: 当c=7时,zks将得3分
第三个例子:无论瑶姐把实数c放在哪 ,zks都无法得到分。

思路:
由于都是正整数,所以定一个区间,0到正无穷,然后把mqj的数字放进这个大区间。0到mqj的数字到正无穷两两相邻之间可以构成很多个小区间。然后再把zks的数字放进去。
去找每个小区间里zks的数字的量,取最大的那个。
注意如果zks的数字跟mqj的数字相同则不计zks的数字,可以直接删掉。
举个例子:
设zks的数字为a,mqj的数字为b。
若是0到b[0]这个区间,假设a[0],a[1],a[2]都小于b[0],可取c为大于0且小于a[0]的数,则a[0],a[1],a[2]比所有b都距离c近。
若是b[0]到b[1]这个区间,假设a[3],a[4],a[5],a[6]都大于b[0]且小于b[1],可取c为区间的中点,则这个区间内的a[3],a[4],a[5],a[6]都满足距离c比所有b近。
显而易见,若a与b重合,则无法满足距离c比所有b近,故删去。

ps:这里还用了unique函数(和sort函数一样位于algorithm头文件),作用是去掉相邻的数的重复的数,本质是将重复的数移动到容器末尾(容器大小不会变),unique函数会返回容器末尾元素的地址,减去初始地址可得size,注意真正去重要先排序再使用这个。

#include
#include
#include
#include
using namespace std ;

const int maxn = 1e5 + 5 ;
long a[maxn] , b[maxn] ;
queue< long > h ;

int main()
{
	ios::sync_with_stdio(false) ;
	cin.tie(0) ;
	cout.tie(0) ;
	
	int n , m ;
	while( cin >> n >> m )
	{
		long i , j , c = 0 , num = 0 ;
		map< long , int > p ;
		
		for( i = 0 ; i < n ; ++i )
			cin >> a[i] ;
		for( i = 0 ; i < m ; ++i )
		{
			cin >> b[i] ;
			p[b[i]]++ ;
		}
		
		b[m] = 0 , b[m+1] = 0x3f3f3f3f ;
		
		sort( b , b + m + 2 ) ;
		sort( a , a + n ) ;
		
		for( i = 0 ; i < n ; ++i )
		{
			if( !p[a[i]] )
				h.push(a[i]) ;
		}
	
		long len = unique( b , b + m + 2 ) - b ;
		
		long count = 0 ;
		for( i = 1 ; i <= len - 1 ; ++i )
		{
			count = 0 ;
			while( !h.empty() )
			{
				if( h.front() < b[i] && h.front() > b[i-1] )
				{
					count++ ;
					h.pop() ;
				}
				else
					break ;
			}
			c = max( c , count ) ;
		}
			
		if( !c )
			cout << "Impossible" << endl ;
		else
			cout << c << endl ;
	

	}
	return 0 ;
 } 

D-山不平何以平天下


刘俊学长在一个深山老林里冒险,这里到处都是山,第i座山的高度记为hi
当hi-1 然而zks是一位魔法师,他可以使一座山凭空消失,而它旁边的两座山会神奇般的连接起来。
例如有7座山,高度为 1 9 1 9 8 1 0 当对第三座山施加魔法时,剩下的六座山为1 9 9 8 1 0
zks希望在释放魔法后,刘俊学长讨厌的山会尽可能的变少。那么最少会有多少座山令刘俊学长讨厌呢? 魔法只能释放一次。

输入
有多组样例测试
第一行为一个整数n,代表有n座山
第二行包含n个正整数 h1,h2,…,hn,代表山的高度
1≤n≤1e5, 0≤hi≤1e9
输出
在释放魔法后,刘俊最少会讨厌的山的数量

样例输入
6
1 1 4 5 1 4
7
1 9 1 9 8 1 0
10
2 1 4 7 4 8 3 6 4 7
样例输出
1
0
2

思路:
在for循环里讨论三种情况:讨厌山数不变、讨厌山数-1、讨厌山数-2(若两座高度相同的讨厌的山之间只隔一座山)。另外注意特判当讨厌的山数为0时直接输出0即可。

ps:其实是较简单的一道思维题,月赛的时候想复杂了给自己写晕了orz。

#include
using namespace std ;

int main()
{
	ios::sync_with_stdio(false) ;
	cin.tie(0) ;
	cout.tie(0) ;
	
	int n , i , j , a[100005] , b[100005] ;
	while( cin >> n )
	{
		int mm = 0x3f3f3f3f , x = 0 ;
		for( i = 0 ; i < n ; ++i )
			cin >> a[i] ;
		for( i = 0 ; i < n ; ++i )
		{
			if( a[i] > a[i-1] && a[i] > a[i+1] && i-1 >= 0 && i+1 < n )
			{
				x++ ;
			}
		}
		if( x == 0 )
		{
			cout << 0 << endl ;
			continue ;
		}
		for( i = 0 ; i < n ; ++i )
		{
			if( a[i] > a[i-1] && a[i] > a[i+1] && a[i+2] > a[i+1] && a[i+3] < a[i+2] && i-1 >= 0 && i+3 < n && a[i] == a[i+2] )
			{
				mm = min( mm , x - 2 ) ;
			}
			else
			{
				if( a[i] > a[i-1] && a[i] > a[i+1] && i-1 >= 0 && i+1 < n )
				{
					if( i-2 >= 0 && i+1 < n && a[i-1] > a[i+1] && a[i-2] < a[i-1] || a[i+1] > a[i-1] && a[i+1] > a[i+2] && i-1 <= 0 && i+2 < n )
					{
						mm = min( mm , x - 0 ) ;
					}
					else
					{
							mm = min( mm , x - 1 ) ;
					}
				}
			}
		}	
		cout << mm << endl ;
	}	 
	
	return 0 ;
 } 

E-排行统计

题:
上周周赛结束了,每个同学都有一个排名,且不存在并列情况
zks在统计协会周赛排名的时候,意外的将一部分同学排名统计错了。
请问,zks将所有同学排名都统计错误的情况有多少种?

输入
第一行输入为一个整数n,代表有n名同学
1≤n≤15

输出
所有同学排名都统计错误的情况数量

样例输入
3

样例输出
2

提示
n=3时,有两种情况:
3 1 2
2 3 1

思路:

错排递推公式:D(n) = ( n - 1 ) * ( D( n - 1 ) + D ( n - 2 ) )

代码一(递归实现):
递归方法比较清晰直接,易于理解,但由于递归本身的问题,效率会较低。

#include
using namespace std ;

long long cp( int n )
{
	if( n == 1 )
	{
		return 0 ;
	}
	if( n == 2 )
	{
		return 1 ;
	}
	return ( n - 1 ) * ( cp( n - 1 ) + cp( n - 2 ) ) ;
}

int main()
{
	int n ;
	cin >> n ;
	cout << cp( n ) << endl ;
	return 0 ;
}

代码二(数组实现):

#include
using namespace std;
  
int main() 
{
    int n ;
    long long d[21] = { 0 , 0 , 1 };
    for( int i = 3 ; i <= 20 ; ++i ) 
	{
        d[i] = ( i - 1 ) * ( d[i-1] + d[i-2] ) ;
    } 
    while( cin >> n ) 
	{
        cout << d[n] <<endl;
    }
    return 0;
}
 

F-买花


五一劳动节要到了,zks想送出n朵花给mqj,他打算提前开始买。但是,因为他有强迫症,所有的花要分k天买(k>1,即不能一天全买完),第一天他可以买任意朵花,之后每一天买花的数量为前一天的两倍,(如若第一天买4朵,第二天就要买8朵,以此类推)。 如果现在离劳动节还有15天(k≤15),请你告诉zks,他能不能刚好买到n朵花。

输入
第一行一个正整数T(1<=T<=10^5),表示数据组数。
接下来T行有T个数,每行一个正整数n(1<=n<=10^9),表示预计买花的数量。
输出
每组数据输出一行,共T行。
判断是否能刚好买到n多花,可以则输出"YES",否则输出"N0" (注意看清输出!)

样例输入
2
21
20
样例输出
YES
N0

提示
数据量大,请用scanf, printf

思路:
设第一天买的花为x朵,第二天买2x朵,一共有3x朵,第三天买4x朵,一共有7x朵,以此类推到十五天就够了,用个数组d存起来,如果要买的花数%d为0,则可以买到。
( yh大佬yyds!)

注意:这题数据有点ex,加速后的cin还是会被卡QAQ,还是乖乖用scanf叭(弱弱吐槽一句scanf写起来真的好麻烦唉)
ps:这题,唉,比赛结束后yh大佬教我的时候我才发现我题目都看错了,我以为是后一天拥有的花是前一天拥有的花的两倍QAQ,今天也被自己蠢哭了呢/。

#include
#include
using namespace std ;
  
int main()
{
    int t ;
    scanf( "%d" , &t ) ;
    int a[20] , d ;
    a[0] = d = 1 ;
    for( int i = 1 ; i < 15 ; ++i )
    {
        d = 2 * d ;
        a[i] = a[i-1] + d ;
    }
    while( t-- )
    {
        long n ;
        scanf( "%ld" , &n ) ;
        int flag = 0 ;
        for( int i = 1 ; i < 15 ; ++i )
        {
            if( n % a[i] == 0 )
            {
                flag = 1 ;
                break ;
            }
        }
      
        if( flag )
            printf( "YES\n" ) ;
        else
            printf( "N0\n" ) ;
    }
    return 0 ;
 } 

G-Race

题:
zks和mqj喜欢赛跑。mqj虽然跑得比较快,但是他在任一时刻领先T米或以上,他就会停下来休息S秒。
现在告诉你mqj的速度V1(m/s)和zks的速度V2(m/s),T(米)和S(秒)的值,以及赛道的长度L(米),请你预测zks和mqj谁会赢。

输入
输入一行,五个正整数V1,V2,T,S,L(L是V1,V2的公倍数)
(1 ≤ V1, V2 ≤ 100,1 ≤ T ≤ 300,1 ≤ S ≤ 10,1 ≤ L ≤ 10000)

输出
输出一行,比赛的结果和获胜者或两人同时到达终点的时间(秒),中间用空格分开
字符串"Mqj"、"Zks"和"Tie"分别表示mqj获胜、zks获胜和他们同时到达终点

样例输入
2 1 1 2 8
样例输出
Tie 8

注意:顺序问题QAQ,mqj是不能连续休息的,如果已经休息了一次,但是zks距离mqj还是大于t米,则mqj要跑一秒再休息。

ps:wa了将近二十次,我以为,只要他们之间的距离大于t米就会一直休息,哭辽

#include
using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    long v1, v2, t, s, p, i, tt = 0;
    cin >> v1 >> v2 >> t >> s >> p;
    long s1 = 0, s2 = 0;
    while (1)
    {
        if (s1 == p || s2 == p)
            break;
        s1 += v1;
        s2 += v2;
        tt++;
        if (s1 - s2 >= t&&s1<p&&s2<p)
        {
            int k;
            for (k = 1; k <= s; ++k)
            {
                s2 += v2;
                if (s2 >= p)
                    break;
            }
            if (k > s)
                tt += s;
            else
                tt += k;
        }
    }
    if (s1 == s2)
    {
        cout << "Tie " << tt << endl;
    }
    else
    {
        if (s1 > s2)
        {
            cout << "Mqj " << tt << endl;
        }
        else
        {
            cout << "Zks " << tt << endl;
        }
    }
    return 0;
}

H-最小互质数


我们定义两个数的互质数当且仅当gcd(a, b) = 1。
现在L手里有n个数,分别为a1,a2,a3 ……an-1,an 。
问,没有在这n个数中出现过并且与这n个数都互质的最小的数是多少。
LL觉得这个问题太简单了,于是她把这个问题交给你来解决。

输入
第一行一个数n (1 ≤ n, ai ≤ 10^5)
接下来n行,每行一个数,分别代表a1,a2,a3 ……an-1,an 。
输出
输出一行代表答案

样例输入
5
1
2
3
4
5
样例输出
7

提示
没有在这n个数中出现的数有:6,7,……
6与2, 3, 4不互质,最小的与这n个数互质的数就是7了。

思路:

显然如果给的数没有1就输出1,有1的话,那答案肯定是在质数里面选啦!
这里可以先用一个欧拉筛素数打表,注意要在里面加一个标记质因数的东西!

///然后oj上一直ac88%,牛客上数据水了倒是ac了。///

如果是给的数里有该质数的倍数那么这个质数也要pass掉!

///昨晚wa了好多次,本来有想到这个的,但是一看数据1e5就有点不确定了,感觉肯定会超时,打完就删掉了QAQ,后悔没有交一发了。///

事实上,如果真的给出1e5个数的话,那么能选的质数也会更少,复杂度差不多是O(n)。

ps:超级感谢mo哥超级耐心的帮我找bug!!!

#include
#include
using namespace std ;
  
const int maxn = 1e6 + 5 ;
int a[maxn] , prime[maxn] , countnum = 0 ;
bool N[maxn] = { false } ;
map < int , int > p ;
  
void isprime( )
{
    int i , j ;
    for( i = 2 ; i <= maxn ; ++i )
    {
        if( !N[i] )
            prime[countnum++] = i ;
        for( j = 0 ; j < countnum ; ++j )
        {
            if( i * prime[j] > maxn )
                break ;
            N[ i * prime[j] ] = true ;
            if( p[ i * prime[j] ] )
            {
                p[i]++ ;
                p[prime[j]]++ ;
            }
            if( i % prime[j] == 0 )
                break ;  
        }
    }
}
  
int main()
{
    int i , j , n , flag = 0 ;
    cin >> n ;
    for( i = 1 ; i <= n ; ++i )
    {
        cin >> a[i] ;
        p[a[i]]++ ;
    }
    if( !p[1] )
    {
        cout << 1 << endl ;
        return 0 ;
    }
    isprime() ;
    for( i = 0 ; i < countnum ; ++i )
    {
        if( !p[ prime[i] ] )
        {
        	for( j = 1 ; j <= n ; ++j )
        	{
        		if( a[j] %  prime[i] == 0 )
				{
					break ;
				 } 
			}
			if( j > n )
				break ;
		}
        
    }
    cout << prime[i] << endl ;
    return 0 ;
}

J-上进的LZ


LZ个上进的人,他的人生没有下坡路,他也讨厌带有”下坡路“的东西。 所以,对于LZ来说,只有非降序的数组才是nice的(如:1,2,2,3,4,5,5);若数组元素个数为1,也满足非降序,也是nice的。 现在有一个长度为n的数组,LZ想知道它的子数组中有多少个数组是nice的。
你能帮帮他吗? 对于子数组的定义,如果可以通过从开头和从结束分别删除若干个(可以为零或全部,前后删除个数不必相同)元素来从数组b获得数组a,则称数组a是数组b的子数组。(子数组包含原数组,但不包含空串)

输入
第一行输入一个整数n(1≤n≤10^5),表示数组的长度。
第二行包含n个空格分隔的整数a1,a2,.,an(0≤ai≤10^9),为数组的元素
输出
输出的给定数组的子数组是nice数组的个数。

样例输入
5
1 2 3 4 5
样例输出
15

思路:
首先遍历,找到比前一个元素小的元素,并标记,存进数组,这个数组相邻的两个数组成一个非降序区间,利用等差数列的和公式去求出每一个区间的子数组个数,然后加起来即可。

ps:这个题月赛的时候敲的真的好坎坷QAQ,两次看错题我也是醉了,后来终于看对了题意,然后用的这个思路敲了一发wa了心态就崩了,应该是当时太浮躁了细节问题没搞好orz

#include
#include
using namespace std ;

const int maxn = 1e5 + 5 ;
long a[maxn] , b[maxn] ;

int main()
{
	ios::sync_with_stdio(false) ;
	cin.tie(0) ;
	cout.tie(0) ;
	
	int n , num = 1 , i ;
	cin >> n ;
	for( i = 1 ; i <= n ; ++i )
		cin >> a[i] ;
	for( i = 2 ; i <= n ; ++i )
	{
		if( a[i] < a[i-1] )
		{
			b[num++] = i ;
		}
	}
	if( !num )
	{
		cout << n+ n * (n-1) / 2 << endl ;
		return 0 ;
	}
	b[num++] = n + 1 ;
	b[0] = 1 ;
	long long c = 0 , s = 0 ;
	while( 1 )
	{
		long long nn = 0 ;
		for( i = b[c] ; i < b[c+1] ; ++i )
		{
			nn++ ;
		}
		if( nn == 1 )
			s += 1 ;
		else 
			s += nn + nn * ( nn - 1 ) / 2  ;
		if( c == num  )
			break ;
		c++ ;
	}
	cout << s << endl ;
	return 0 ;
}

K-填数


小莫拿到了一个数,数的大小不超过五位数,且不含前导0。并且每一位的数字都只出现一次。然后zks将其中的几位数字标记为’?’
而’?'可以表示从1~9之间的任何数,但不能和现有的数重复出现。小莫需要统计出有多少种数可以正好被m整除,并打印出来
如果小莫不会这个问题,他会被zks叫成老莫的,请你快帮帮他!

输入
第一行输入两个正整数n,m n代表字符串的长度,m代表除数 1≤m≤1e9
第二行输入一个字符串,其中至少包含一个’?’
字符串长度不超过5位
输出
从小到大输出符合的数,每个数独占一行
如果不存在,则输出NO

样例输入
4 5
?23?
样例输出
1235
4235
6235
7235
8235
9235

思路一:
取最小值和最大值遍历。

ps:这题方法很简单,不过我太菜了,写出来好多bug,第一遍好不容易打出来结果输出都没有,心态崩了,休息了一下,纠正了半小时bug,然后突然就ac了。

#include
#include
#include
#include
using namespace std ;

#define bug(a) cout << "* " << a << endl ;

int main()
{
	int n , m , i , ff = 0 ;
	int b[10] = { 0 , 1 , 10 , 100 , 1000 , 10000 , 100000 } ; 
	cin >> n >> m ;
	string a ;
	cin >> a ;
	int len = a.length() , s = 0 , c[10] = { 0 } ;
	map< int , int > p , q ;
	map< int , int >:: iterator it ;
	for( i = 0 ; i < len ; ++i )
	{
		if( a[i] != '?' )
		{
			p[ a[i] - '0']++ ;
			s += (a[i]-'0') * b[len - i] ;
		}
	}
	for( i = b[len] ; i < b[len + 1] ; ++i )
	{
		if( i % m != 0 || i % 10 == 0 )
			continue ;
		
		int o = i , flag = 0 , num = 0 ;
		q.clear() ;
		while( o )
		{
			c[num++] = o % 10 ;
			if( o%10 == 0 )
			{
				flag = 1 ;
				break ;
			}
			if( len - num >= 0 && a[len - num] != '?' && c[num-1] != a[len-num] - '0' )
			{
				flag = 1 ;
				break ;
			}
			else
			{
				if( len - num >= 0 && a[len - num] == '?' && ( p[c[num-1]] || q[c[num-1]] ) )
				{
					flag = 1 ;
					break ;
				}
			}
			q[c[num-1]]++ ;
			o /= 10 ;
		}
	
		if( flag )
			continue ;
		cout << i << endl ;
		ff = 1 ;
	}
	if( !ff )
		cout << "NO" << endl ;
	return 0 ;
}

思路二:
用暴力搜索dfs!

ps:我还是不太会用dfs,这个是看了克总的代码,感觉看懂了,然后自己又打了一遍,克总yyds!!!

#include
#include
#include
using namespace std ;

map< int , int > p ; 
int sum = 0 , len , n , m ;
string s ;

void dfs( int now , int num )
{
	if( now == len )
	{
		if( num % m == 0 )
		{
			cout << num << endl ;
			sum++ ;
		}
		return ;
	}
	else
	{
		if( s[now] == '?' )
		{	
			for( int i = 1 ; i <= 9 ; ++i )
			{
				if( !p[i] )
				{
					p[i]++ ;
					dfs( now + 1 , num * 10 + i ) ;
					p[i] = 0 ;
				}
			
			}	
		}
		else
		{
			dfs( now + 1 , num * 10 + s[now] - '0' ) ;
		}
	}
}

int main()
{
	ios::sync_with_stdio(false) ;
	cin.tie(0) ;
	cout.tie(0) ;
	
	cin >> n >> m >> s ;
	len = s.length() ;
	for( int i = 0 ; i < len ; ++i )
	{
		if( s[i] != '?' )
		{
			p[ s[i] - '0' ]++ ;
		}
	}
	dfs( 0 , 0 ) ;
	if( !sum )
		cout << "NO" << endl ;
	return 0 ;
 } 

你可能感兴趣的:(做题笔记和反思)