黑龍江農墾科技職業學院喜迎寒假多校聯賽2(快樂ak場)

快樂ak場 (沒做可以做一下 - > 本次比賽鏈接

  • 前言
    這次比賽難嗎,我認爲挺容易的(每道題都挺容易的)。
    我後面一個半小時都在玩,我感覺我就是個撒比,這種難度都做不來(A 和 D 沒做),還不好好看題,我感覺自己真的挺無語的,重點是考的都是我已經學過的,沒有盲區,害,萌新直接去世,腦子瓦特。

    希望大家一起加油,好好努力,發現不足,及時補進


  • 第一題 數組截取

思想:雙指針 + 快速讀取

  • 快速讀取模板
inline int read() {
   
    
		char c = getchar(); int n = 0;
		while (c < '0' || c > '9') {
   
     c = getchar(); }
		while (c >= '0' && c <= '9') {
   
     n = (n << 1) + (n << 3) + (c & 15); c = getchar(); }
		return n;
 	}                 ///快讀模板

這個直接背就行了,不需要什麼思想。

  • 快寫模板
void write(int x)
	{
   
    
		if(x<0)	putchar('-'),x=-x;
		if(x>9)	write(x/10);
		putchar(x%10+'0');
	}           ///快寫模板

好了正式開始,講雙指針。
傳送門 - > 題目A,點擊這裏

  • 解析

    雙指針思想就是用兩個指針,指向一個區間,主要分兩種
    第一種:同時指向開頭 (這題)
    第二種:分別指向開頭和結尾

    在這裏插入圖片描述
    舉個例子,讓 i 和 j 兩個指針同時指向 【3,3,1,1,1,0,0,0,3,3】這個區間開頭
    讓 j 這個指針不斷右移,直到找到 j 到 i 的區間裏面之和大於 k (例題就是 3)
    在這裏插入圖片描述
    這裏的 i 和 j 這個範圍區間爲6,我們就讓 i 這個指針右移
    在這裏插入圖片描述
    這樣就區間就之和 就不大於 3(也就是k) 然後進行判斷區間是否等於 k ,如果等於就記錄距離。
    以此類推,輸出我們找到最大的距離






  • 注意事項

    1 題目數據很大(超過了題目規定的範圍),所以開大點數組
    2 快讀
    3 long long 類型


代碼如下

#include<iostream>
//全開longlong,保險
using namespace std;
inline long long read() {
   
     
		char c = getchar(); long long n = 0;
		while (c < '0' || c > '9') {
   
      c = getchar(); }
		while (c >= '0' && c <= '9') {
   
      n = (n << 1) + (n << 3) + (c & 15); c = getchar(); }
		return n;
 	}
long long a[20000010];
int main(){
   
     
    long long  n,m,ans=0,sum=-1;
    n=read(),m=read();//快讀
    for(long long i=0,j=0;i<n;i++){
   
     
        a[i]=read();//快讀
        ans+=a[i];//累加區間和
        while(ans>m) ans-=a[j++];// 當ans>m時,j 指針右移
        if(ans==m) sum=max(sum,i-j+1); //等於記錄距離
    }
    cout<<sum;//輸出最大距離
    return 0;//收工
}

想練一道雙指針的題嗎?
練習題 傳送門 - > 快去完成吧


第二題 羣友們在排列數字

  • 主要思想:DFS

這 - > 題目

這題本來要用DFS的,可是這屬於全排列的範疇,也可以用STL裏的全排列神器

next_permutation 不是很瞭解的 傳送門 -> next_permutation詳細用法

這道題如果使用神器的話就太簡單了,把區間裏的數全累加起來取模就行,判斷次數

  • 第一種題解 STL的做法

#include<iostream>
#include<algorithm>
using namespace std;
int n,k;
long long a[15];
int main(){
   
      
    int ans=0;
    cin>>n>>k;
    for(int i=0;i<n;i++) a[i]=i;
    do{
   
      
        long long sum=0;
        for(int i=0;i<n;i++){
   
      
            sum=sum*10+a[i];
        }
        if(sum%k==0) ans++;
    }while(next_permutation(a,a+n));
    if(ans) cout<<ans;
    else cout<<-1;
    return 0;
}

再說一下DFS的做法(學過的同學可以看一下,沒學過的,學完再看吧,可以看第一種解法)
這題是DFS入門題沒啥子好講(真的就是入門題,DFS新手村的題目)

  • 沒有注意事項

代碼

#include<iostream>

using namespace std;

const int N=15;
int p[N];
bool s[N];
int n,k;
long long ans;
void dfs(int u){
   
      
    if(u==n){
   
      
        long long sum=0;
        for(int i=0;i<n;i++){
   
      
            sum=sum*10+p[i];
        }
        if(sum%k==0&&sum) ans++;
        return ;
    }
    for(int i=0;i<n;i++){
   
      
        if(!s[i]){
   
      
            p[u]=i;
            s[i]=true;
            dfs(u+1);
            s[i]=false;
        }
    }
}
int main(){
   
      
    cin>>n>>k;
    dfs(0);
    if(ans) cout<<ans;
    else cout<<-1;
    return 0;
}

歡迎看看我的DFS博客 傳送門 - > DFS講解
DFS這題 原型傳送門 - > 排序問題


第三題 gg查成績

主要思想:前綴和

這題又是前綴和新手村的題目(入門題,學了前綴和就會)
如果用枚舉,會超時的喲

  • 簡單講一下 前綴和

有兩個數組 a[ N ]和s[ N ];
a[ N ]是數據,s[ N ]是a[0]到 a[N] 的區間和
公式 s[ i ]=s[ i-1 ]+a[ i ]
求一段區間 [ l , r ] 和 ans = s[ r ] - s [ l - 1];
這種求法時間複雜度是O(1)的(非常快)



  • 前綴和公式
S[i] = a[1] + a[2] + ... a[i]    //s[i] 數組
a[l] + ... + a[r] = S[r] - S[l - 1]  //求區間和

代碼如下

#include<iostream>

using namespace std;
const int N=1e6+10;
int n,m;
long long a[1000005]; //這裏我只開了區間和數組,也就是s[N],因爲這題不需要用到a[N];
int main(){
   
       
    cin>>n>>m;
    for(int i=1;i<=n;i++){
   
            // i 要從1開始避免特判  i=0, i-1=-1,這就錯誤了 a[0]=0;
        long long x;
        scanf("%lld",&x);
        a[i]=a[i-1]+x;   //累加,得前綴和數組
    }
    for(;m;m--){
   
           
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%lld\n",a[r]-a[l-1]); 
    }
    return 0;
}

本題原型 趕緊秒了他 - > 前綴和入門題


第四題 issue與lifehappy給學生分組

主要思想: 二分答案

題目 這裏

這題二分有點不好寫,D和E算是這裏水平還可以的題目了
二分我就不多介紹了,就是 對半取

  • 解析

在這裏插入圖片描述
就是用答案證結論 看是大還是小了 然後就相當應縮短區間

主要是怎麼取很重要

比方說我們有一個大小爲 mid 最大值

比 mid 大的區間就不成立 我們就要再給一組 ,看我們最終的組和題目給我們的組數的大小,來縮短查找區間

在這裏插入圖片描述
如果mid爲9,我們就這麼劃分區間,我只能講到這裏,具體看代碼吧,說的比較抽象

代碼

#include<iostream>

using namespace std;
const int N=2e6+10;
long long n,m;
long long a[N];
bool f(long long x){
   
        
    long long ans=0,len=0;//len是組數
    for(int i=0;i<n;i++){
   
        
        if(ans+a[i]<=x) ans+=a[i];  
        else len++,ans=a[i]; //再劃分一個區間
    }
    if(ans) len++; //沒劃分的數的再劃分一個區間
    return len>m;
}
int main(){
   
        
    cin>>n>>m;
    for(int i=0;i<n;i++) scanf("%lld",&a[i]);
    long long l=0,r=1e11+1;
    while(l<r){
   
        
        long long mid=l+r>>1;//二分
        if(f(mid)) l=mid+1; //組多了 就增大最大值
        else r=mid; //否則縮小最大值
    }
    cout<<l;
    return 0;
}

這裏我們一定要處理好臨界情況,整數二分最難搞的就是臨界情況

給大家一個二分題,練練手吧 - > 整數二分
再來個浮點二分 - > 浮點二分

模板放下面 自己看

  • 整數二分
bool check(int x) {
   
        /* ... */} // 檢查x是否滿足某種性質
// 區間[l, r]被劃分成[l, mid]和[mid + 1, r]時使用:
int bsearch_1(int l, int r)
{
   
        
    while (l+1 < r)
    {
   
        
        int mid = (l + r) 1;
        if (check(mid)) r = mid;    // check()判斷mid是否滿足性質
        else l = mid ;
    }
    return l;
}
// 區間[l, r]被劃分成[l, mid - 1]和[mid, r]時使用:
int bsearch_2(int l, int r)
{
   
        
    while (l < r)
    {
   
        
        int mid = (l + r + 1)1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}
  • 浮點二分
bool check(double x) {
   
        /* ... */} // 檢查x是否滿足某種性質

double bsearch_3(double l, double r)
{
   
        
    const double eps = 1e-6;   // eps 表示精度,取決於題目對精度的要求
    while (r - l > eps)
    {
   
        
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

這裏有STL裏有關於二分的函數 分別是 lower_bound( ) 和 upper_bound( ) ,這兩個只能用在有序數組裏,切記

關於lower_bound( )和upper_bound( )的常見用法

好了下午再補充,我先休息了,嘻嘻


第五題 刪刪刪越小越好

題目

主要思想:單調棧

肯定有人說,這怎麼可以是單調棧呢?其實他是字符的單調棧,並非數字,原理是一模一樣的。

1 怎麼樣得到最小值

因爲我們有k次刪除機會,但我們不管怎麼刪,數的位數是不會變的
所以我們只需要把高位的數儘可能的小就行了
這時就要用到單調棧思想了

2 啥是單調棧

其實很簡單,就是我們要得到一個單調遞增的區間,把搗亂的數據刪除。

例如 如圖
在這裏插入圖片描述
我們有十次機會刪除 我們要讓前面的位數呈單調遞增,這樣高位就是最小的。
12345897 到 7 時 不呈單調遞增,所以我們把 7 前面的 8和 9 刪掉


在這裏插入圖片描述

就變成了123477了,我們現在還有8次刪除權限,後面讀入1,就變成了1234771,又不呈現單調了,現在我們就要把2,3,4,7,7刪了
在這裏插入圖片描述
**就變成了11了,現在我們有三次權限,我們再讀入1187,這時把 8刪了,我們還有2次刪除機會,
以此類推,直至呈現單調遞增或刪除權限沒有了,爲止。

在這裏插入圖片描述


這個例題得到的數爲 1114164979 因爲刪除權限用完了,所以我們就輸出**

挺簡單的,但要想到單調棧的思想很難。

代碼如下

#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e7+10;
long long k,tt,hh=1;
char a[N],b[N];//這裏位數太大,必須用字符來輸入
int main(){
   
         
    scanf("%s%lld",a,&k);
    for(int i=0;a[i];i++){
   
         
        while(k&&tt&&b[tt]>a[i]) k--,tt--; //k用完或前面沒有字符,我們就不進行刪除
        b[++tt]=a[i]; //滿足單調性質,就讀入
    }
    while(b[hh]=='0'&&hh<tt) hh++; //消除前導零,hh爲開頭第一個非零的字符
    for(int i=hh;i<=tt-k;i++) cout<<b[i]; //若已經呈單調,但k沒有用完
	   return 0;						//我們就輸出前hh到tt-k    
}							                       

題目還是要練一下的 - > 單調棧


第六題 happy的異或運算

思想:懂異或,就能做出來了,很簡單的思維題

啥是異或?

異或符號爲 ^,這個在計算機的主要功能很多,你們自己可以去看,我這裏講簡單點。
瞭解一下這三個運算
1 ^ 0 = 1
0 ^ 0 = 0
1 ^ 1 = 0



知道這三個運算就夠了,因爲計算機是二進制存儲的,所以只有0 和 1 的運算
這題要求最大值 我們只要讓所有二進制位都爲一就是最大值了
因爲 1 到 n 一定可以找到 兩個數 1 和 0 互補,使所有位置上都爲一,這就是這題思想

例如 4 = 100(二進制), 最大值就爲 7 = 111(二進制)

代碼如下,提供兩種寫法

第一種是我寫的

#include<iostream>
  
using namespace std;
long long n,sz=0; 
int main(){
   
          
    cin>>n;
    if(n==1){
   
          
    	cout<<0;   //因爲1的異或最大值爲0,所有特判一下,1^1=0 
    	return 0;
    }
    while(sz<=n) sz=(sz*2+1);
    cout<<sz<<endl;  
    return 0;
}

第二種是位運算

#include<iostream>
  
using namespace std;
long long n;
int main(){
   
          
    cin>>n;
    long long b=1;
    while(b<=n) b<<=1; //使用右移運算符
    cout<<b-1;
    return 0;
}

思維題就沒啥可推薦的,一抓一大把。0.0


第七題 Alan%%%
題目

思維:他要求啥,就做啥

這題沒啥可講的,就講幾個string庫的小知識吧

1 find函數 找到你想要的字符串位置
例如 字符串 string str = “abcd”
str.find(“cd”),他就會返回cd字符串的位置,位置爲2.

2 getline函數
gets沒啥區別,作用是讀入一行字符串,包括空格,直到碰到回車爲止

3 因爲c++的string重載了+運算符

   string a = "123"
   string b = "456"
 	string c = a+b
   c=="123456"

代碼如下

#include<iostream>

using namespace std;
string a;
int n,ans;
int main(){
   
           
    cin>>n;
    cin.ignore();//喫掉回車,防止getline吃了上一行的回車
    for(;n;n--){
   
             
        string b;
        bool flag=false;
        int sum=0;
        getline(cin,a); //讀入
        for(int i=0;i<a.size();i++){
   
           
            if(a[i]!=' ') b+=a[i]; //將空格屏蔽
            if(a[i]=='%') sum++;	//數 % 個數
        }
        if(b.find("Alan")<b.size()) flag=true; //用find函數找一下Alan,如果不在這個範圍,就說明沒有
        if(flag) ans+=sum;
    }
    cout<<ans;
    return 0;
}

代碼題沒啥可講


第八,九題 cg寫項目

思維:要求排序

這裏我們要介紹sort的自定義寫法

就是自己定義比較規則
第一種 STLsort的自定義

#include<iostream>
#include<algorithm>
using namespace std;
struct ss{
   
            
    string t,m,x,h;    //用戶名t,密碼m,性別x,電話h
    int id;
}s[100005];
int n;
bool cmp(ss a,ss b){
   
                        //這裏我們定義了比較的規則
    if(a.t.size()!=b.t.size()) return a.t.size()<b.t.size();  // t的大小不同,這t的大小 小的在前
    if(a.t!=b.t) return a.t<b.t;    //t的大小相同則比較t,t小的在前
    return a.id<b.id;          //若都相同,這id小的在前
}
int main(){
   
            
    cin>>n;
    for(int i=0;i<n;i++) s[i].id=i,cin>>s[i].t>>s[i].m>>s[i].x>>s[i].h;
    sort(s,s+n,cmp);
    for(int i=0;i<n;i++) cout<<s[i].t<<" "<<s[i].m<<" "<<s[i].x<<" "<<s[i].h<<endl;
    return 0;
}

第二種 重載 < 運算符(高手都是第二種,大家搖身變大佬,哈哈

#include<iostream>
#include<algorithm>
using namespace std;
struct ss{
   
            
    string t,m,x,h;
    int id;
    bool operator < (const ss &a)const{
   
              
        if(t.size()!=a.t.size()) return t.size()<a.t.size();
        if(t!=a.t) return t < a.t;
        return  id<a.id;
    }
}s[100005];
int n;
int main(){
   
            
    cin>>n;
    for(int i=0;i<n;i++) s[i].id=i,cin>>s[i].t>>s[i].m>>s[i].x>>s[i].h;
    sort(s,s+n);
    for(int i=0;i<n;i++) cout<<s[i].t<<" "<<s[i].m<<" "<<s[i].x<<" "<<s[i].h<<endl;
    return 0;
}

也可以用快排和歸排,但是好麻煩,所有自己可以去試,只有把<重載了就行了
這裏有一道要求排序題 - > 建議使用重載<去做排序


最後一道簽到題
不講了,這都講,那太沒無語了

#include<iostream>
 
using namespace std;
const int N=1e6+10;
int n,m=0x3f3f3f3f;
int main(){
   
             
    int t,x;
    cin>>n;
    for(int i=1;i<=n;i++){
   
             
        cin>>x;
        if(m>x)  m=x,t=i;
    }
    cout<<t<<endl;
    return 0;
}

感謝大家的觀看,我花了好久打完了,希望能幫到大家
完結撒花
點點贊,辛苦死我了/(ㄒoㄒ)/~~
在這裏插入圖片描述


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章