C++学习笔记1

C++学习笔记1

码农世界 2024-05-12 前端 86 次浏览 0个评论

A. 求出那个数

题目描述

求出一个最小的正整数 x x x,使得 x x x 每位数字的和恰好为 n n n。

输入格式

第一行一个正整数 T T T,代表测试数据的组数。

接下来 T T T 行每行一个正整数 n n n。

  • 1 ≤ T ≤ 1000 1\le T\le1000 1≤T≤1000
  • 0 ≤ n < 1000 0\le n<1000 0≤n<1000

    输出格式

    对于每组输入,输出最小的 x x x。

    样例

    输入 #1

    2
    5
    14
    

    输出 #1

    5
    59
    
    1. 尽量用 9 9 9,这样能使数位最小;
    2. n n n 不够 9 9 9 时,作为第一位输出;
    3. 若 n n n 为 0 0 0,特判输出 0 0 0。
    #include 
    //#define int long long
    using namespace std;
    void solve()
    {
    	int n;
    	cin >> n;
    	if (n == 0)
    	{
    		printf("0\n");
    		return ;
    	}
    	string s = "";
    	while (n > 0) n -= 9,s += '9';
    	cout << n + 9 << s.substr(0,s.size()-1) << '\n';
    }
    signed main()
    {
    	int TTT;
    	cin >> TTT;
    //	TTT = 1;
    	while (TTT--) solve();
    	return 0;
    }
    

    B. 田忌赛马·Easy

    齐使者如梁,孙膑以刑徒阴见,说齐使。齐使以为奇,窃载与之齐。齐将田忌善而客待之。忌数与齐诸公子驰逐重射。孙子见其马足不甚相远,马有上、中、下辈。于是孙子谓田忌曰:“君弟重射,臣能令君胜。”田忌信然之,与王及诸公子逐射千金。及临质,孙子曰:“今以君之下驷与彼上驷,取君上驷与彼中驷,取君中驷与彼下驷。”既驰三辈毕,而田忌一不胜而再胜,卒得王千金。于是忌进孙子于威王。威王问兵法,遂以为师。

    ——「史记·孙子吴起列传第五」

    在千年以前,孙膑就能靠着过人的智谋,通过巧妙地调整比赛的顺序,让三战皆背的田忌翻身成为两胜一败的赢家,也为自己赢得了别人的尊敬。在千年以后的今天,赛马依然是一项热门的娱乐活动,不过今天你要面对的却是更加困难的问题。

    你和对手各自都有 N N N 匹马,要进行 N N N 场比赛。一匹马只能出场一次,同场比赛中速度快的马获得胜利。如果两匹马的速度一样的话,那么就是平局。你的对手会像齐王那样在第一场出速度最快的马,第二场出次快的马, … \dots …,第 N N N 场出速度最慢的马。

    而你为了获胜,当然会按照某种策略安排你的 N N N 匹马的出场顺序。除此之外,你还可以决定比赛的时间,全部 N N N 场比赛都会在你决定的那一天举行。在比赛之前,你为了获胜会不辞辛苦的训练你的每一匹马;而你的对手自我感觉良好,不会训练他的马。每一匹马的素质不同,我们用 a i a_i ai​ 来表示你的第 i i i 匹马的速度。每经过一天的训练,你的马的速度就会增加 1 1 1。

    现在你拿到了对手的 N N N 匹马的资料,请你尽快计算训练的天数 M M M,以使得在第 M + 1 M+1 M+1 天比赛的时候,你可以安排一个出场顺序使得你可以在全部的 N N N 场比赛中至少获胜 K K K 场。

    输入格式

    第一行给出一个正整数 T T T,代表测试数据的组数。

    每组测试数据有 3 3 3 行,第一行有两个以空格分隔的数字 N , K N,K N,K,含义如题目种描述。

    第二行有 N N N 个以空格分隔的正整数,第 i i i 个数字代表你第 i i i 匹马的速度 a i a_i ai​。

    第三行有 N N N 个以空格分隔的正整数,第 j j j 个数字代表你对手第 j j j 匹马的速度 c j c_j cj​。

    • 1 ≤ T ≤ 30 1\le T\le30 1≤T≤30
    • 1 ≤ K ≤ N ≤ 1 0 5 1\le K\le N\le 10^5 1≤K≤N≤105
    • 0 ≤ a i , c j ≤ 1 0 9 0\le a_i,c_j\le 10^9 0≤ai​,cj​≤109

      输出格式

      对于每组测试数据输出一个非负整数 M M M,代表在第 M + 1 M+1 M+1 天举办的赛马比赛中你可以至少赢得 K K K 场。

      如果不止有一个 M M M 满足条件,请输出最小的那个。

      样例

      输入 #1

      2
      4 2
      3 1 2 4
      0 4 3 2
      1 1
      10
      10
      

      输出 #1

      0
      1
      
      1. 第 M + 1 M+1 M+1 天的时候,你的马匹的速度分别是 a 1 + M , a 2 + M , a 3 + M , … , a n + M a_1+M,a_2+M,a_3+M,\dots,a_n+M a1​+M,a2​+M,a3​+M,…,an​+M,需要派出最好的 K K K 匹马,对上对手最差的 K K K 匹马;
      2. 假设我们最好的 K K K 匹马是 a 1 ≤ a 2 ≤ a 3 ≤ ⋯ ≤ a k a_1\le a_2\le a_3\le\dots\le a_k a1​≤a2​≤a3​≤⋯≤ak​,对手最差的 K K K 匹马是 c 1 ≤ c 2 ≤ c 3 ≤ ⋯ ≤ c k c_1\le c_2\le c_3\le\dots\le c_k c1​≤c2​≤c3​≤⋯≤ck​;
      3. 我们要训练的天数就是: max ⁡ ( 0 , max ⁡ i ( c i − a i + 1 ) ) \max(0,\max_i(c_i-a_i+1)) max(0,maxi​(ci​−ai​+1))。
      #include 
      #define int long long
      using namespace std;
      int a[100010],b[100010];
      bool cmp(int a,int b) {return a > b;}
      void solve()
      {
      	int n,m,ans = 0;
      	cin >> n >> m;
      	for (int i = 1;i <= n;i++) cin >> a[i];
      	for (int i = 1;i <= n;i++) cin >> b[i];
      	sort(a+1,a+n+1,cmp);
      	sort(b+1,b+n+1);
      	for (int i = 1,j = m;i <= m;i++,j--) ans = max(ans,b[i]-a[j]+1);
      	cout << ans << '\n';
      }
      signed main()
      {
      	int TTT;
      	cin >> TTT;
      //	TTT = 1;
      	while (TTT--) solve();
      	return 0;
      }
      

      C. 田忌赛马·Hard

      齐使者如梁,孙膑以刑徒阴见,说齐使。齐使以为奇,窃载与之齐。齐将田忌善而客待之。忌数与齐诸公子驰逐重射。孙子见其马足不甚相远,马有上、中、下辈。于是孙子谓田忌曰:“君弟重射,臣能令君胜。”田忌信然之,与王及诸公子逐射千金。及临质,孙子曰:“今以君之下驷与彼上驷,取君上驷与彼中驷,取君中驷与彼下驷。”既驰三辈毕,而田忌一不胜而再胜,卒得王千金。于是忌进孙子于威王。威王问兵法,遂以为师。

      ——「史记·孙子吴起列传第五」

      在千年以前,孙膑就能靠着过人的智谋,通过巧妙地调整比赛的顺序,让三战皆背的田忌翻身成为两胜一败的赢家,也为自己赢得了别人的尊敬。在千年以后的今天,赛马依然是一项热门的娱乐活动,不过今天你要面对的却是更加困难的问题。

      你和对手各自都有 N N N 匹马,要进行 N N N 场比赛。一匹马只能出场一次,同场比赛中速度快的马获得胜利。如果两匹马的速度一样的话,那么就是平局。你的对手会像齐王那样在第一场出速度最快的马,第二场出次快的马, … \dots …,第 N N N 场出速度最慢的马。

      而你为了获胜,当然会按照某种策略安排你的 N N N 匹马的出场顺序。除此之外,你还可以决定比赛的时间,全部 N N N 场比赛都会在你决定的那一天举行。在比赛之前,你为了获胜会不辞辛苦的训练你的每一匹马;而你的对手自我感觉良好,不会训练他的马。每一匹马的素质不同,我们用 a i a_i ai​ 来表示你的第 i i i 匹马的速度。每经过一天的训练,你的第 i i i 匹马的速度就会增加 b i b_i bi​。

      现在你拿到了对手的 N N N 匹马的资料,请你尽快计算训练的天数 M M M,以使得在第 M + 1 M+1 M+1 天比赛的时候,你可以安排一个出场顺序使得你可以在全部的 N N N 场比赛中至少获胜 K K K 场。

      输入格式

      第一行给出一个正整数 T T T,代表测试数据的组数。

      每组测试数据有 3 3 3 行,第一行有两个以空格分隔的数字 N , K N,K N,K,含义如题目种描述。

      第二行有 N N N 个以空格分隔的正整数,第 i i i 个数字代表你第 i i i 匹马的速度 a i a_i ai​。

      第三行有 N N N 个以空格分隔的正整数,第 j j j 个数字代表你对手第 j j j 匹马的速度 c j c_j cj​。

      • 1 ≤ T ≤ 100 1\le T\le100 1≤T≤100
      • 1 ≤ K ≤ N ≤ 1 0 4 1\le K\le N\le 10^4 1≤K≤N≤104
      • 0 ≤ a i , c j ≤ 1 0 8 0\le a_i,c_j\le 10^8 0≤ai​,cj​≤108
      • 0 ≤ b i ≤ 100 0\le b_i\le100 0≤bi​≤100

        输出格式

        对于每组测试数据输出一个非负整数 M M M,代表在第 M + 1 M+1 M+1 天举办的赛马比赛中你可以至少赢得 K K K 场。

        如果不止有一个 M M M 满足条件,请输出最小的那个。

        如果没有任何 M M M 满足条件,请输出 -1。

        样例

        输入 #1

        2
        3 2
        1 2
        2 1
        3 2
        0
        3
        4
        1 1
        1 0
        2
        

        输出 #1

        1
        -1
        
        1. 第 M + 1 M+1 M+1 天的时候,你的马匹的速度分别是 a 1 + M × b 1 , a 2 + M × b 2 , a 3 + M × b 3 , … , a n + M × b n a_1+M\times b_1,a_2+M\times b_2,a_3+M\times b_3,\dots,a_n+M\times b_n a1​+M×b1​,a2​+M×b2​,a3​+M×b3​,…,an​+M×bn​;
        2. 不难发现,若训练了 D D D 天之后能赢 x x x 场,那么训练 D + 1 D+1 D+1 天获胜的场数必然 ≥ x \ge x ≥x 场,所以我们可以二分枚举答案进行 c h e c k check check;
        3. 尽量找实力相当的马来比。
        #include 
        #define int long long
        using namespace std;
        int n,m;
        int b[100010];
        struct node {int a,b;}a[100010];
        bool cmp(int a,int b) {return a > b;}
        bool check(int x) //训练 x 天
        {
        	vector  now; //存储训练后马匹的速度
        	for (int i = 1;i <= n;i++) now.push_back(a[i].a+x*a[i].b);
        	sort(now.begin(),now.end(),cmp);
        	int j = 0,win = 0;
        	for (int i = 1;i <= n;i++) if (now[j] > b[i]) j++,win++;
        	return win >= m;
        }
        void bs(int l,int r)
        {
        	int ans;
        	while (l <= r)
        	{
        		int mid = (l+r)/2;
        		if (check(mid)) ans = mid,r = mid-1;
        		else l = mid+1;
        	}
        	cout << ans << '\n';
        }
        void solve()
        {
        	cin >> n >> m;
        	for (int i = 1;i <= n;i++) cin >> a[i].a >> a[i].b;
        	for (int i = 1;i <= n;i++) cin >> b[i];
        	sort(b+1,b+n+1,cmp);
        	int l = 0,r = 1e14;
        	if (!check(r)) cout << "-1\n"; //没有任何 M 满足条件
        	else bs(l,r);
        }
        signed main()
        {
        	int TTT;
        	cin >> TTT;
        //	TTT = 1;
        	while (TTT--) solve();
        	return 0;
        }
        

        D. 放置方案数

        现在有 k k k 种颜色的小球,每一种颜色的小球有若干个,有 n n n 个盒子排成一排,现在要往盒子里放球,每一个盒子需要放 1 1 1 个小球,要求相邻的盒子之间最多只有 2 2 2 个连续颜色相同的小球,问你有多少种方案,由于答案很大,请你对 1 0 9 + 7 10^9+7 109+7 取模。

        输入格式

        第一行输入一个整数 T T T,代表有 T T T 组测试数据。

        接下来 T T T 行,每行给出两个正整数 n , k n,k n,k,含义如题。

        • 1 ≤ T ≤ 1 0 3 1\le T\le10^3 1≤T≤103
        • 1 ≤ n , k ≤ 1 0 5 1\le n,k\le10^5 1≤n,k≤105

          输出格式

          对于每组测试数据,在一行中输出答案。

          样例

          输入 #1

          2
          1 1
          3 2
          

          输出 #1

          1
          6
          
          1. 最多可以有连续两个盒子放相同颜色的球,所以只需要考虑连续的三个盒子即可;
          2. 用 d p i 0 dp_{i_0} dpi0​​ 表示第 i i i 个盒子放和第 i − 1 i−1 i−1 个盒子球颜色不同的球的方案数;
          3. 用 d p i 1 dp_{i_1} dpi1​​ 表示第 i i i 个盒子放和第 i − 1 i−1 i−1 个盒子球颜色相同的球的方案数;
          4. d p i 0 = ( d p i − 1 0 + d p i − 1 1 ) × ( k − 1 )   %   ( 1 0 9 + 7 ) dp_{i_0}=(dp_{{i-1}_0}+dp_{{i-1}_1})\times(k-1)\ \%\ (10^9+7) dpi0​​=(dpi−10​​+dpi−11​​)×(k−1) % (109+7);
          5. d p i 1 = d p i − 1 0 dp_{i_1}=dp_{{i-1}_0} dpi1​​=dpi−10​​。
          6. 最终的答案取 ( d p n 0 + d p n 1 )   %   m o d (dp_{n_0}+dp_{n_1})\ \%\ mod (dpn0​​+dpn1​​) % mod。

            十年 OI 一场空,不开 long long 见祖宗!

          #include 
          #define int long long
          using namespace std;
          const int mod = 1000000007;
          int dp[100010][2];
          void solve()
          {
          	int n,m;
          	cin >> n >> m;
          	dp[1][0] = m;
          	dp[1][1] = 0;
          	for (int i = 2;i <= n;i++)
          	{
          		dp[i][0] = (dp[i-1][0]+dp[i-1][1]) * (m-1) % mod;
          		dp[i][1] = dp[i-1][0];
          	}
          	cout << (dp[n][0]+dp[n][1]) % mod << '\n';
          }
          signed main()
          {
          	int TTT;
          	cin >> TTT;
          //	TTT = 1;
          	while (TTT--) solve();
          	return 0;
          }
          

          E. 密码破解

          密码学是研究编制密码和破译密码的技术科学。研究密码变化的客观规律,常应用于编制密码以保守通信秘密的。从古代传递情报道现在电脑的通信一直扮演着一个十分重要的角色。相信你一定听说过「凯撒密码」,它属于是一种替换密码。一种凯撒密码的替换方式是 A → D , B → E , C → F , … , X → A , Y → B , Z → A A\to D,B\to E,C\to F,\dots,X\to A,Y\to B,Z\to A A→D,B→E,C→F,…,X→A,Y→B,Z→A。以数学的方式来说,我们让 A = 0 , B = 1 , C = 2 , … , Z = 25 A=0,B=1,C=2,\dots,Z=25 A=0,B=1,C=2,…,Z=25,使用密钥 x x x 加密明文 a a a 得到的密文就是 :

          E x ( a ) = ( a + x ) mod ⁡ 26 E_x(a)=(a+x) \operatorname{mod} 26 Ex​(a)=(a+x)mod26

          以现在的计算机技术,凯撒密码是很容易破解的,即使我们不知道其中用来加密的密钥 x x x 的值,我们依然可以借助计算机强大的算力通过频率分析方法将其暴力解出。当密文长度足够大的情况下,可以先分析密文中每个字母出现的频率,然后将这一频率与正常情况下的该语言字母表中所有字母的出现频率做比较。例如在英语中,正常明文中字母 E E E 和 T T T 出现的频率特别高,而字母 Q Q Q 和 Z Z Z 出现的频率特别低,而在法语中出现频率最高的字母是 E E E,最低的是 K K K 和 W W W。可以通过这一特点,分析密文字母出现的频率,可以估计出正确的密钥 x x x。

          这里我们要介绍一种改良版的凯撒密码。现在你有一组密钥 x 1 , x 2 , x 3 , … , x l x_1,x_2,x_3,\dots,x_l x1​,x2​,x3​,…,xl​,要加密的信息 a 1 , a 2 , a 3 , … , a n a_1,a_2,a_3,\dots,a_n a1​,a2​,a3​,…,an​ 得到密文 c 1 , c 2 , c 3 , … , c n c_1,c_2,c_3,\dots,c_n c1​,c2​,c3​,…,cn​。我们拿第一个密钥的字母 x 1 x_1 x1​ 加密 a 1 a_1 a1​,拿第二个密钥的字母 x 2 x_2 x2​ 加密 a 2 a_2 a2​, … \dots …。如果密钥用完了,我们就拿前面得到的密文来用,也就是拿 c 1 c_1 c1​ 来加密 a l + 1 a_{l+1} al+1​。

          c i = { a i + x i mod ⁡ 26 i ≤ l a i + c i − l mod ⁡ 26 i > l c_i = \begin{cases} a_i+x_i \operatorname{mod} 26 & i \le l \\ a_i+c_{i-l} \operatorname{mod} 26 & i>l \end{cases} ci​={ai​+xi​mod26ai​+ci−l​mod26​i≤li>l​

          现在,给你几组用同样的密钥加密的明文密文配对,请你写程序来破解出密钥。

          输入格式

          第一行一个正整数 T T T,代表测试数据的组数。

          每组测试数据在第一行给出一个正整数 N N N,代表有几对明文密文配对。

          接下来 N N N 行每行给出两个以空格分隔且只由大写字母组成的字符串 s 1 , s 2 s_1,s_2 s1​,s2​​,前面的代表明文,后面的是加密后的密文。

          • 1 ≤ T ≤ 200 1\le T\le200 1≤T≤200
          • 1 ≤ N ≤ 10 1\le N\le10 1≤N≤10
          • 1 ≤ ∣ s 1 ∣ = ∣ s 2 ∣ ≤ 300 1\le\lvert s_1\rvert=\lvert s_2\rvert\le300 1≤∣s1​∣=∣s2​∣≤300

            输出格式

            对于每组输入在一行中输出一个字符串,代表能够将 N N N 组明文分别加密成对应密文的密钥。

            如果有多种可能的密钥,请输出最短的那个。

            如果没有任何符合的密钥,请输出 -。

            样例

            输入 #1

            2
            1
            VAMRI VCYMK
            2
            CAKES DEOHW
            CAKES DEOHW
            

            输出 #1

            ACM
            BEE
            
            #include 
            #define int long long
            using namespace std;
            const int N = 20;
            int n;
            string s1[N],s2[N];
            bool check(string str,string ming,string mi)
            {
            	//ming -> 明文
            	//mi -> 密文
            	string s = "";
            	for (int i = 0;i < ming.size();i++)
            	{
            		char tmp = char(((ming[i]+str[i])%26) + 'A');
            		s += tmp;
            		str += tmp;
            	}
            	return s == mi;
            }
            string pre(string str[],int n)
            {
            	sort(str,str+n,greater()); //倒序排序
            	if (!check(str[0],s1[0],s2[0])) return "-"; //注意是字符串
            	for (int i = 1;i < n;i++)
            		if (str[0].substr(0,str[i].size()) != str[i] || !check(str[0],s1[i],s2[i]))
            			return "-";
            	return str[0];
            }
            void solve()
            {
            	string str[N],s[N];
            	cin >> n;
            	for (int i = 0;i < n;i++)
            	{
            		cin >> s1[i] >> s2[i];
            		for (int j = 0;j < s1[i].size();j++)
            			str[i] += 'A' + ((s2[i][j]-s1[i][j]+26) % 26);
            		int id = 1;
            		for (int j = 0;j < str[i].size();j++)
            		{
            			if (str[i].substr(j) != s2[i].substr(0,str[i].size()-j))
            				id = j+1;
            			else
            				break;
            		}
            		s[i] = str[i].substr(0,id);
            	}
            	cout << pre(s,n) << '\n';
            }
            signed main()
            {
            	int TTT;
            	cin >> TTT;
            //	TTT = 1;
            	while (TTT--) solve();
            	return 0;
            }
            

转载请注明来自码农世界,本文标题:《C++学习笔记1》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,86人围观)参与讨论

还没有评论,来说两句吧...

Top