深基刷題記錄(1)

P1424 小魚的航程(改進版)

在這裏插入圖片描述

#include<bits/stdc++.h> //包含了所有C++頭文件的頭文件
using namespace std;
int main()
{
    unsigned long long n,ans=0; //坑就坑在這兒。天數都那麼大了,總路程還會小嗎???
    int x;
    cin >> x >> n; //輸入星期和持續天數
    for(int i=0;i<n;i++)
    {
        if((x!=6)&&(x!=7)) //只要星期不等於6和7
            ans += 250; //總長度增加250
        if(x==7) //當x等於7的時候
        x=1; // x歸位爲1
        else //其他情況下(x不等於7的時候)
            x++; //x自加1
    }
    cout << ans; //輸出總路程
    return 0;
}

P1009 階乘之和

在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
int a[2000],sum[2000]; //數組 a是階乘的打表 數組 sum是階乘相加 

void multiply(int a[],int n) //乘法 
{
	int jw=0; //進位
	for(int i=0;i<2000;i++) //全乘了
	{
		a[i]=a[i]*n+jw;
		jw=a[i]/10;
		a[i]%=10;
	}
}

void add(int a[],int sum[]) //加法 
{
	int jw=0; //進位
	for(int i=0;i<2000;i++)
	{
		sum[i]+=a[i]+jw;
		jw=sum[i]/10;
		sum[i]%=10;
	}
}

int main()
{
	int n;
	cin>>n;
	a[0]=1; //記得初始化爲 1
	for(int i=1;i<=n;i++)
	{
		multiply(a,i);
		add(a,sum);
	}
	int flag=0;
	for(int i=1999;i>=0;i--)
	{
		if(flag)
			cout<<sum[i];
		else if(sum[i]!=0)
		{
			flag=1;
			cout<<sum[i];
		}
	}
	return 0;
}

高精度乘低精度,所以可以正序計算,再倒序輸出

P1980 計數問題

在這裏插入圖片描述

//解法一
#include <bits/stdc++.h>
using namespace std;
  
int main() 
{
   int n, x;
   cin >> n >> x;
   stringstream ss;
   for (n++; --n; ss << n);     //把1-n的值都存放到字符串流中
   string s = ss.str();
   cout << count(s.begin(), s.end(), x + '0') << endl;    //運用count函數直接出結果,簡簡單單
   return 0;
}


//解法二
#include<iostream>
using namespace std;
int main()
{
    long long n,i,x,b,c,t=0;
    cin>>n>>x;//輸入範圍與要查的數字;
    for(i=1;i<=n;i++)//一到n進行循環;
    {
        b=i;//爲了不改變i的值,就把i賦值給一個數;
        while(b!=0)//如果b不等於0,繼續循環;
        {
            c=b%10;//求是否是x,是的話計數器加一;
            b=b/10;//求下一個數字是否爲x;
            if(c==x) t++;計數器加一;
        }
    }
    cout<<t<<endl;//輸出計數器的數字;
    return 0;//結束
}

P2669 金幣

在這裏插入圖片描述

# include <stdio.h>
int main()
{
    int K,N,coin=0;
    scanf("%d",&K);               //輸入總天數K
    for(N=1;K-N>=0;K-=N++)       //第1天騎士可獲得1枚金幣
        coin+=N*N;               //在接下來的連續N天裏,騎士每天可獲得N枚金幣
    printf("%d\n",coin+K*N);   //輸出騎士總共可獲得的金幣數
    return 0;
}

P1420 最長連號

在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
int f[10010], a[10010], n, ans=1;//DP做法
int main()
{
	cin >> n;
	for (int i = 1; i <= n; ++i) cin >> a[i];
	memset(f,1,sizeof(f))
	for (int i = 2; i <= n; ++i)
	{
		if(a[i-1]+1==a[i])
		{
			f[i]=f[i-1]+1;
			ans=max(ans,f[i]);
		}
	}
	cout << ans;
}

P1161 開燈

在這裏插入圖片描述

#include<bits/stdc++.h> //萬能頭文件
#define f(i,j,n) for(i=j;i<=n;i++) //for循環簡寫,福利福利~
using namespace std;
int main()
{
    ios::sync_with_stdio(false); //cin,cout快讀快輸,寫scanf和printf的就不要加了,會RE
    int n,t,i,j,ans=0;
    double a; //爲了保險我們還是開double
    cin>>n;
    f(i,1,n)
    {
        cin>>a>>t;
        f(j,1,t)
            ans^=int(j*a); //重點:位運算,直接異或,這裏注意要用int強制把j*a的值轉換成整型
    }
    cout<<ans<<endl; //輸出ans即可
    return 0; //華麗麗地結束
}

0 異或(^)任何數 都等於 那個數

P5731 【深基5.習6】蛇形方陣

在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
int a[15][15];
int main()
{
	int n,k=1,x=1,y=0;;
	cin>>n;
	while (k<=n*n)
	{
		while(y<n&&!a[x][y+1])a[x][++y]=k++;
		while(x<n&&!a[x+1][y])a[++x][y]=k++;
		while(y>1&&!a[x][y-1])a[x][--y]=k++;
		while(x>1&&!a[x-1][y])a[--x][y]=k++;
	}
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=n;j++)printf("%3d",a[i][j]); //注意每個數字有都會佔用 3 個字符,前面使用空格補齊
		printf("\n");	
	}	
	return 0;
}

P1789 【Mc生存】插火把

在這裏插入圖片描述
在這裏插入圖片描述

#include <bits/stdc++.h> 
using namespace std;
int n, m, k, a, b, ans;
int s[5005][5005];
bool pd(int x, int y) { //判斷是否越界 
    if(x < 1 || y < 1 || x > n || y > n) return 0;
    return 1;
}
int main() {
    scanf("%d%d%d", &n, &m, &k); //讀入 
    for(int i = 1; i <= m + k; i++) { //由於計算火把和螢石的步驟很像,所以合併了 
        scanf("%d%d", &a, &b); //讀入座標 
        for(int x = -2; x <= 2; x++)
            for(int y = -2; y <= 2; y++) //枚舉5*5的方陣(通過計算距離) 
                if((i > m || abs(x) + abs(y) <= 2) && pd(x + a, b + y))
                //如果是螢石(i > m)或者x與y的座標差的和不超過2(想一想爲什麼)並且
                //沒有越界就標記 
                    s[x + a][b + y]++;
    }
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            ans += s[i][j] == 0; //枚舉每一個方格,看看是不是==0(即沒有亮光) 
    printf("%d\n", ans); //輸出結果 
    return 0;
}

這種做法感覺很厲害,主要是思路很奇特

P1320 壓縮技術(續集版)

在這裏插入圖片描述
在這裏插入圖片描述

#include <bits/stdc++.h>//luogu福利
using namespace std;

char a,b='0';//注意了:一定是賦值爲'0';
int n,ans[1000001],zz=1;//zz是指針的意思,我用來存儲第幾位

int main()
{
 while(cin>>a)
 {
 	n++;
 	if(a==b)
 		ans[zz]++;
 	else
 		ans[++zz]++,//等效於:zz=zz+1;ans[zz]++
 		b=a;//上面用 , 不用 ; 的原因是我沒有打{ }
 }
 cout<<sqrt(n);//平方根,用到了<cmath>或者是<math.h>,也就是一行的行數
 for(int i=1 ; i<=zz ; i++)
     cout<<" "<<ans[i];
}

這種做法感覺很厲害,主要是思路很奇特

P1205 [USACO1.2]方塊轉換 Transformations(自改)

題目描述

將行列都爲 n 的正方形圖案旋轉90°,其中圖案是由從 1 … n*n 的數字組成,將起始圖案和旋轉後的圖案打印出來

輸出樣例(以 n=3 爲例)

123
456
789

741
852
963
#include<bits/stdc++.h>
using namespace std;
const int N=4; //可隨題目而變
int a[N][N],b[N][N];
void output(int c[N][N])
{
	for(int i=1;i<N;i++)
	{
		for(int j=1;j<N;j++)
		cout<<c[i][j];
		cout<<endl;
	}
}
int main()
{
	int k=1;
	for(int i=1;i<N;i++)
	for(int j=1;j<N;j++)
	a[i][j]=k++;
	output(a);cout<<endl;
	for(int i=1;i<N;i++)
	for(int j=1;j<N;j++)
	b[j][N-i]=a[i][j];
	output(b);
	return 0;
}

P1957 口算練習題

在這裏插入圖片描述
在這裏插入圖片描述

#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main ()
{
	int n;
	cin>>n;//輸入n 
	char ch;//要輸入的字母 
	string s[n];//存放最後的表達式 
	for(int i=0;i<n;i++)//開始循環輸入 
	{
		string st;//用來存放數字 
		stringstream io;//轉換數字 
		int a,b,ans=0;//ans是答案 
		if(!(cin>>a))//利用了cin的性質 
		{
			cin.clear();
			cin>>ch>>a;
		}
		cin>>b;
		io<<a;io>>s[i];io.clear();//接下來對ch進行判斷 
		if(ch=='a')
		{
			ans=a+b;
			s[i]+='+';
			io<<b;io>>st;io.clear();//io每次用完後要記得清空哦
			s[i]+=st;
			s[i]+='=';
			io<<ans;io>>st;io.clear();
			s[i]+=st;
		}//以此類推
		if(ch=='b')
			{
				ans=a-b;
				s[i]+='-';
				io<<b;io>>st;io.clear();
				s[i]+=st;
				s[i]+='=';
				io<<ans;io>>st;io.clear();
				s[i]+=st;
			}
		if(ch=='c')
			{
				ans=a*b;
				s[i]+='*';
				io<<b;io>>st;io.clear();
				s[i]+=st;
				s[i]+='=';
				io<<ans;io>>st;io.clear();
				s[i]+=st;
			}
	}
	for(int i=0;i<n;i++)//循環輸出結果 
	{
		cout<<s[i]<<endl;
		cout<<s[i].size();
		if(i!=n-1)cout<<endl;
	}
}

如果你定義了一個 int 型,那麼當 cin 輸入表達式的值是就會檢測輸入的是不是數字,如果程序發現用戶輸入了錯誤內容時,會返回 0,否則返回 1,(次代碼還完美的運用 stringstream 流)

P1308 統計單詞數

在這裏插入圖片描述
在這裏插入圖片描述

#include <iostream>
#include <string>
//命名空間
using namespace std;
int main()
{
    //定義兩個字符串
    string a;
    string b;
    //用string庫,調用getline, 直接讀入一整行
    getline(cin,a);
    getline(cin,b);
    //轉換大小寫,可以都轉換爲大寫,或者小寫
    for (int i=0;i<a.length();++i){
        a[i]=tolower(a[i]);
    }
    for (int i=0;i<b.length();++i){
        b[i]=tolower(b[i]);
    }
    //因爲連起來的不算,所以要在前後加一個空格,一定要是同樣多的,同量減同量,等於同量
    a=' '+a+' ';
    b=' '+b+' ';
    //先看看會不會找不到,用a.find()和string::npos
    if (b.find(a)==string::npos){
        cout<<-1<<endl;
    }
    //如果找得到
    else {
        int alpha=b.find(a);
        int beta=b.find(a),s=0;//計數器初始化爲0
        while (beta!=string::npos){
            ++s;//計數器
            beta=b.find(a,beta+1);
        }
        cout<<s<<" "<<alpha<<endl;//輸出第一個和總共有幾個
    }
    //函數返回值爲0,結束整個程序
    return 0;
}

因爲題目要求:連起來的不算,所以要在前後加一個空格
計數的方法用的也很棒

P3741 honoka的鍵盤

在這裏插入圖片描述
在這裏插入圖片描述

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char a[102];
int main()
{
    gets(a);
    gets(a);
    int ans=0;
    for(int i=0;i<strlen(a);i++)
    {
        if(a[i]=='V' && a[i+1]=='K')
        {
            ans++;
            a[i]='X';
            a[i+1]='X';
        }
    }
    for(int i=0;i<strlen(a);i++)
    {
        if(a[i]!='X' && a[i]==a[i+1])
        {
            ans++;
            break;
        }
    }
    printf("%d",ans);
    return 0;
}

在這裏插入圖片描述
思路很棒,學習了

P1321 單詞覆蓋還原

在這裏插入圖片描述

#include <bits/stdc++.h> 
using namespace std;
int boy,girl,n;
string a;
int main()
{
    cin>>a;
    n=a.length();
    for(int i=0;i<n-2;i++)
      boy+=(a[i]=='b'||a[i+1]=='o'||a[i+2]=='y');
    for(int i=0;i<n-3;i++)
      girl+=(a[i]=='g'||a[i+1]=='i'||a[i+2]=='r'||a[i+3]=='l');
    cout<<boy<<endl<<girl;               
    return 0;
}

在這裏插入圖片描述
我想複雜了,實際一個個字符對比就好了

P1597 語句解析

在這裏插入圖片描述

#include<cstdio>
using namespace std;
int a[3];char s1,s2;
int main()
{
    while (scanf("%c:=%c;",&s1,&s2)==2)//充分利用c++語言優勢
     a[s1-'a']=s2>='0' && s2<='9' ? s2-'0' : a[s2-'a']; //賦值語句簡潔明瞭
    printf("%d %d %d",a[0],a[1],a[2]);
}

和乙級那題有異曲同工之妙

P5461 赦免戰俘

簡單的說就是打印這樣的圖(2n * 2n
在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
int n;
int a[1234][1234];
int main()
{
	scanf("%d",&n);
	n = (1<<n);
	a[0][n+1] = 1; //右上角的元素賦值爲 1
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)
		{
			a[i][j] = a[i-1][j] ^ a[i-1][j+1]; //a[i][j] = (a[i-1][j] + a[i-1][j+1]) % 2
			printf("%d ",a[i][j]);             //異或和(a+b)%2有相同的效果
		}
		printf("\n");
	}
	return 0;
}

這規律找的絕了(之所以不適用於楊輝三角,是因爲這是正方形,那是三角形)

P1498 南蠻圖騰

在這裏插入圖片描述
先說楊輝三角的遞推寫法

int a[12]={1}; //全局作用域
for(int i=0;i<12;i++) //局部作用域
{
	for(int j=i;j>=0;j--)
	{
		a[j]^=a[j-1];
		cout<<a[j];
	}
	cout<<endl;
}

output:
            1
           1 1 
          1 0 1 
         1 1 1 1 
        1 0 0 0 1 
       1 1 0 0 1 1 
      1 0 1 0 1 0 1 
     1 1 1 1 1 1 1 1 
    1 0 0 0 0 0 0 0 1 
   1 1 0 0 0 0 0 0 1 1 
  1 0 1 0 0 0 0 0 1 0 1
 1 1 1 1 0 0 0 0 1 1 1 1

此題可以看做楊輝三角的改版題

#include<iostream>
using namespace std;
int n,a[1030]={1};
int main(){
	cin>>n;
    for(int i=0;i<1<<n;++i){
        for(int j=1;j<(1<<n)-i;++j)cout<<" ";//前導空格
		for(int j=i;j>=0;--j)a[j]^=a[j-1];//修改數組
		if(!(i%2))for(int j=0;j<=i;++j)cout<<(a[j]?"/\\":"  ");//奇數行
		else for(int j=0;j<=i;j+=2)cout<<(a[j]?"/__\\":"    ");//偶數行
		cout<<endl;
    }
    return 0;
}

行數是2n,以這個數組爲基礎,奇數行遇 1 輸出"/\",偶數行遇連續兩個 1 輸出"/__\",遇0補上相應的空格即可

P2415 集合求和

在這裏插入圖片描述

#include <stdio.h>
int main(){
    long long ans=0;
    int n=0,i,a;
    while(scanf("%d",&a)!=EOF)ans+=a,n++;
    for(i=1;i<n;i++)ans*=2;
    printf("%lld",ans);
    return 0;
}

規律就是:全部加起來 * 2 的(元素個數 - 1)次方

P2670 掃雷遊戲

在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
bool a[105][105];//一張地圖,有雷爲一,無雷爲零 
int main()
{
    memset(a,0,sizeof(a));//地圖最開始清空 
    int n,m;
    char tmp;
    cin>>n>>m; 
    for(int i=1;i<=n;i++)//讀入地圖 
    {
        for(int j=1;j<=m;j++) 
        {
            cin>>tmp;//讀入每一個點 
            if(tmp=='*') a[i][j]=1;//如果是地雷就將這個點設爲一 
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]==1) printf("*"); //如果是地雷不用輸出數字 
            else
            {
                printf("%d",a[i+1][j+1]+a[i+1][j-1]+a[i+1][j]+a[i][j+1]+a[i][j-1]+a[i-1][j+1]+a[i-1][j]+a[i-1][j-1]);
                //將旁邊的雷加起來輸出 
            }
        }
        printf("\n");
    }
    return 0;//愉快的結束了主程序 
}

模擬

P4924 [1007]魔法少女小Scarlet

在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
int g[510][510],tot,f[510][510];//f數組充當臨時數組 
int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			g[i][j]=++tot;
	for(int i=1;i<=m;i++) {
		int a,b,r,opt;
		scanf("%d %d %d %d",&a,&b,&r,&opt);//下面的分析都是針對那一塊矩陣而言的 
		if(opt==0) {//第i行第j個 變成倒數第i列第j個 順時針 
			for(int i=a-r;i<=a+r;i++)
				for(int j=b-r;j<=b+r;j++)
					f[a-b+j][a+b-i] = g[i][j];
			for(int i=a-r;i<=a+r;i++)
				for(int j=b-r;j<=b+r;j++)
					g[i][j] = f[i][j];
		}
		else { //第i行第j個 變成第i列倒數第j個 逆時針 
			 for(int i=a-r;i<=a+r;i++)
				for(int j=b-r;j<=b+r;j++)
					f[a+b-j][b-a+i] = g[i][j];
			 for(int i=a-r;i<=a+r;i++)
				for(int j=b-r;j<=b+r;j++)
					g[i][j] = f[i][j];
		}
	}
	for(int i=1;i<=n;i++) {//輸出結果咯 
		for(int j=1;j<=n;j++)
			printf("%d ",g[i][j]);
		printf("\n");
	}
	return 0;
}

實戰性,用到了數組圖案的旋轉的方法

P1328 生活大爆炸版石頭剪刀布

在這裏插入圖片描述
在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200 + 10;
int n, na, nb, a[MAXN], b[MAXN], cnta, cntb;
int vs[5][5] = {{0,0,1,1,0},{1,0,0,1,0},{0,1,0,0,1},{0,0,1,0,1},{1,1,0,0,0}}; //得分表的處理 
int main()
{
    cin >> n >> na >> nb;
    for(int i = 0; i < na; i++) cin >> a[i];
    for(int i = 0; i < nb; i++) cin >> b[i];
    for(int i = 0; i < n; i++)
    {
        cnta += vs[a[i % na]][b[i % nb]]; //週期循環 
        cntb += vs[b[i % nb]][a[i % na]];
    }
    cout << cnta << " " << cntb << endl;
    return 0;
}

循環模擬,vs數組左邊代表我右邊代表你,贏了+1 輸了+0

P1518 [USACO2.4]兩隻塔姆沃斯牛 The Tamworth Two

在這裏插入圖片描述
在這裏插入圖片描述

#include<cstdio>
bool zt[160005];//10*10*10*10*4*4=160000,開大一點以防萬一
char mp[11][11];
int cx,cy,cf,fx,fy,ff,xx[4]={-1,0,1,0},yy[4]={0,1,0,-1},nt,stp;
int main()
{
    for(int i=0;i<10;i++)
    scanf("%s",mp[i]);//讀入
    for(int i=0;i<10;i++)
    for(int j=0;j<10;j++)
    {
        if(mp[i][j]=='F')//遇到農夫
        fx=i,fy=j;//設定初始座標
        if(mp[i][j]=='C')//遇到牛
        cx=i,cy=j;//設定初始座標
    }
    while(1)
    {
        if(fx==cx&&fy==cy)//相遇了
        {
            printf("%d",stp);//輸出步數
            return 0;//退出
        }
        nt=fx+fy*10+cx*100+cy*1000+ff*10000+cf*40000;//生成特徵值
        if(zt[nt])//如果出現過了,則無解
        {
            printf("0");
            return 0;
        }
        zt[nt]=1;//保存特徵值
        if(fx+xx[ff]<0||fx+xx[ff]>=10||fy+yy[ff]<0||fy+yy[ff]>=10||mp[fx+xx[ff]][fy+yy[ff]]=='*')//判斷農夫是否還能向前走
        ff=(ff+1)%4;//如果不行,轉向
        else fx=fx+xx[ff],fy=fy+yy[ff];//否則繼續向前
        if(cx+xx[cf]<0||cx+xx[cf]>=10||cy+yy[cf]<0||cy+yy[cf]>=10||mp[cx+xx[cf]][cy+yy[cf]]=='*')//判斷牛是否還能向前走
        cf=(cf+1)%4;//如果不行,轉向
        else cx=cx+xx[cf],cy=cy+yy[cf];//否則繼續向前
        stp++;//增加步數
    }
    return 0;
}

模擬,記錄的特徵值包括座標和方向,令我感到好奇的是這樣暴力沒有超時

P1067 多項式輸出

在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,a;
	cin>>n;
	for(int i=n;i>=0;i--)
	{
		cin>>a;
		if(a)
		{
			if(i!=n&&a>0)cout<<"+";     //根據正負、是否爲最高此項決定加號
            if(abs(a)>1||i==0)cout<<a; //輸出係數(係數不爲正負1或指數爲0)
            if(a==-1&&i)cout<<"-";    //-1係數特判,常數項已特判
            if(i>1)cout<<"x^"<<i;    //二次及以上輸出指數
            if(i==1)cout<<"x";    	//一次項
		}
	}
	return 0;
}

坑點很多,希望有空再寫一遍

P1098 字符串的展開

在這裏插入圖片描述
在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
int p1,p2,p3,i=0,k;
char ch[300],be,af,f,j,p;//p用於輸出; 
int main()
{
	scanf("%d %d %d %s",&p1,&p2,&p3,ch);//輸入;
	while(ch[i]) //當ch[i]有值時;
	{
		be=ch[i-1];af=ch[i+1];f=ch[i];//f存儲ch[i],便於判斷; 
		if(f=='-'&&af>be&&(be>='0'&&af<='9'||be>='a'&&af<='z')){//意思是ch[i]若爲'-',就判斷其前後是否滿足條件,滿足進入循環; 
			for(p3==1?j=be+1:j=af-1; p3==1?j<af:j>be; p3==1?j++:j--){
				p=j;//j是整形變量,p是字符型變量,這樣是將p賦值爲ASCII碼爲j的字符; 
				if(p1==2)//是否大寫; 
					p=(p>='a')?p-32:p;//如果是字母就轉成大寫 
				else if(p1==3) p='*';//是否輸出'*' 
				for(k=0; k<p2; k++)//輸出p2個 
					printf("%c",p);
			}
		} 
		else
			printf("%c",f);//如果ch[i]是非'-'或者其前後不滿足條件,就原樣輸出;
		i++;//一定要放在後面,不然會出錯QAQ;
	}
	return 0;
}

字符串整體接收,單個字符的打印,遇到 ‘–’ 號就將其展開

P1065 作業調度方案(跳過)

難度最大的純模擬題

R33754906 記錄詳情

在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
vector<int> mul(vector<int> &A, int b) //A爲高精度數,b爲低精度數
{
	// C = A * b, A >= 0, b > 0
    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size() || t; i ++ )
    {
        if (i < A.size()) t += A[i] * b; //用來解決最高位進位的問題
        C.push_back(t % 10); //保留下最右邊一位
        t /= 10;
    }
    return C;
}
set<int> st; 
int main()
{
	vector<int> s={1};
	int n;cin>>n;
	int i=2;
	while(n>0)
	{
		st.insert(i);
		n-=i;
		if(n<0)
		{
			int k=abs(n);
			if (k==1)
			{
				st.erase(2);
				st.erase(i);
				st.insert(i+1);
			}
			else if(st.find(k)!=st.end())
				st.erase(k);
		}
		i++;
	}
	set<int>::iterator it;
	for(it = st.begin(); it != st.end(); it++)
	{
		cout<<*it<<' ';
		s=mul(s,*it);
	}
	cout<<endl;
	reverse(s.begin(),s.end());
	for(vector<int>::iterator t = s.begin(); t != s.end(); 	t++)
		cout<<*t;
    return 0;
}

在這裏插入圖片描述
我的方法是:用 set 存儲元素,用 vector 計算高精度

P1045 麥森數

在這裏插入圖片描述

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int f[1001],p,res[1001],sav[1001];//乘法要開兩倍長度
void result_1()
{
    memset(sav,0,sizeof(sav));
    for(register int i=1;i<=500;i+=1)
        for(register int j=1;j<=500;j+=1)
            sav[i+j-1]+=res[i]*f[j];//先計算每一位上的值(不進位)
    for(register int i=1;i<=500;i+=1)
    {
        sav[i+1]+=sav[i]/10;//單獨處理進位問題,不容易出錯
        sav[i]%=10;
    }
    memcpy(res,sav,sizeof(res));//cstring庫裏的賦值函數,把sav的值賦給res
}
void result_2()//只是在result_1的基礎上進行了細微的修改
{
    memset(sav,0,sizeof(sav));
    for(register int i=1;i<=500;i+=1)
        for(register int j=1;j<=500;j+=1)
            sav[i+j-1]+=f[i]*f[j];
    for(register int i=1;i<=500;i+=1)
    {
        sav[i+1]+=sav[i]/10;
        sav[i]%=10;
    }
    memcpy(f,sav,sizeof(f));
}
int main()
{
    scanf("%d",&p);
    printf("%d\n",(int)(p*log10(2)+1));
    res[1]=1;
    f[1]=2;//高精度賦初值
    while(p!=0)//快速冪模板
    {
        if(p%2==1)result_1();
        p/=2;
        result_2();
    }
    res[1]-=1;
    for(register int i=500;i>=1;i-=1)//注意輸出格式,50個換一行,第一個不用
        if(i!=500&&i%50==0)printf("\n%d",res[i]);
        else printf("%d",res[i]);
    return 0;
}

2p - 1 與 2p 有着相同的位數,因爲 2 的次方滿足了最後一位不爲零的要求,所以減一後位數並不會改變,直接套求位公式;
總體是高精度套快速冪,而且這種大數有補零,所以用整型數組的高精度最好,最關鍵的是階乘之和不會以 0 結尾

補充:乘法要開兩倍長度、乘法 先相乘 再進位

階乘非零末尾

給定一個數,讓你求出這個數階乘的非零末位

#include<iostream>
using namespace std;//使用namespace
int a,c,i;//設置變量a,c,i
int main()//主函數的起始
{
    cin>>a;//輸入變量a(爲題目中給定的的數)
    i=1;//先將循環變量i設爲1
    c=1;//將變量c初始值設爲1(用於存儲階乘的結果)
    for(i=1;i<=a;i++)//當循環變量i小於等於變量a時,執行下方語句,每次將變量i加1(即從1循環到a的所有數)
    {
        c=c*i%1000000;//將變量c乘變量i取末7位,完成階乘運算且控制了數值大小
        while(c%10==0)//在每次運算中,看看末位是否爲0,若爲0,執行循環體(爲了去除末尾所有的0
        {
            c=c/10;//每次將末位的0去掉,直到末尾非0
        }
    }
    cout<<c%10<<endl;//輸出變量c的末位即爲結果
    return 0;//結束主函數的運行
}

簡單模擬

P1116 車廂重組

在這裏插入圖片描述

#include<iostream>
#include<cstdio>
using namespace std;
long n,i,j,t,s,a[10000];
int main()
{
	cin>>n;
	for(i=1;i<=n;i++)
	cin>>a[i];
	for(i=1;i<=n-1;i++)
	for(j=1;j<=n-i;j++)
	if(a[j]>a[j+1])
	{
		swap(a[j],a[j+1]);
		s++;
	}
	cout<<s;
	return 0;
}

就是冒泡排序

P2241 統計方形(數據加強版)

在這裏插入圖片描述

#include<iostream>
using namespace std;
long long n,m,rec,sqr;
int main() {
    cin>>n>>m;
    for(int i=0; i<n; i++)//循環,從 n-0到 n-(n-1)
        for(int j=0; j<m; j++) {//循環,從 m-0到 m-(m-1)
            if(i==j) sqr+=(n-i)*(m-j);//如果 i==j,說明是正方形
            else rec+=(n-i)*(m-j);//如果不等說明是矩形
        }
    cout<<sqr<<" "<<rec<<endl;//輸出
    return 0;
}

內部長方形計算方法:(n-b)*(m-a) (a≠b)

內部正方形計算方法:(n-b)*(m-a) (a=b)

證明思路(題解第一條)

P1618 三連擊(升級版)

在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
int a[10]={0,1,2,3,4,5,6,7,8,9};
int main()
{
    int A,B,C,h=0;
    cin>>A>>B>>C;
    int t=A*B*C;
    A=t/A;
    B=t/B;
    C=t/C;
    do{
        if((100*a[1]+10*a[2]+a[3])*A==(100*a[4]+10*a[5]+a[6])*B&&(100*a[1]+10*a[2]+a[3])*A==(100*a[7]+10*a[8]+a[9])*C)//如果符合比例;
        {
            cout<<a[1]<<a[2]<<a[3]<<" "<<a[4]<<a[5]<<a[6]<<" "<<a[7]<<a[8]<<a[9]<<endl;//輸出
            h++;
        }
    }while(next_permutation(a+1,a+10));//STL中的下一個排列函數;
    if(h==0) cout<<"No!!!";//沒有解輸出NO;
    return 0;
}

累乘驗證,next_permutation 輸出

#include<bits/stdc++.h>
using namespace std;
int r,a[100],n;
void dfs(int k){//搜索第k個數
    if(k>r){
        for(int i=1;i<=r;i++){
            cout<<setw(3)<<a[i];//輸出,場寬爲三
        }
        cout<<endl;
        return ;//回到前一層
    }
    for(int i=a[k-1]+1;i<=n;i++){
        a[k]=i;
        dfs(k+1);//直接進行下一次調用
    }
}  
int main()  
{   
    cin>>n>>r;
    dfs(1);
    return 0;  
}

精緻又巧妙的 dfs

P1036 選數

在這裏插入圖片描述

#include<bits/stdc++.h>
using namespace std;
int a[20];
bool prime(int k)
{
	if(k<=1) return false;
	for(int i=2;i<=(double)sqrt(k);i++)
		if(k%i==0) return false;
	return true;
}
int dfs(int step,int start,int end,long long a_sum)
{
	if(step==0) return prime(a_sum);
	int sum=0;
	for(int i=start;i<end;i++)
	{
		sum+=dfs(step-1,i+1,end,a_sum+a[i]);
	}
	return sum;
}
int main()
{
    int n,k,ans;
    cin>>n>>k;
    for(int i=0;i<n;i++)cin>>a[i];
    ans=dfs(k,0,n,0);
    cout<<ans;
    return 0;
}

又一精緻又巧妙的 dfs

P3392 塗國旗

在這裏插入圖片描述
在這裏插入圖片描述

#include<iostream>
#include<algorithm>
using namespace std;
int n,m,ans=0x7fffffff,w[51],b[51],r[51];
string s;
inline int check(char c){
    int tot=0;
    for(int i=0;i<m;++i)
        if(s[i]!=c)++tot;
    return tot;    
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;++i){
        cin>>s;
        w[i]=w[i-1]+check('W');
        b[i]=b[i-1]+check('B');
        r[i]=r[i-1]+check('R');
    }
    for(int i=1;i<n-1;++i)
        for(int j=i+1;j<n;++j)
            ans=min(ans,w[i]+b[j]-b[i]+r[n]-r[j]);
    cout<<ans;        
    return 0;
}

在這裏插入圖片描述

P3654 First Step (ファーストステップ)

在這裏插入圖片描述
在這裏插入圖片描述

#include <iostream>
using namespace std;
int n,m,r,ans,dx[2]={0,1},dy[2]={1,0};//位移向量,分別是朝下和朝右
char map[105][105];
void skim(int x,int y,int i,int j)//dfs
{
    if(j>r){//滿足條件則ans++
        ++ans;
        return ;
    }
    if(map[x][y]!='.'||x<0||y<0||x>=n||y>=m)//處理越界和障礙
        return ;
    skim(x+dx[i],y+dy[i],i,j+1);
    return ;
}
int main()
{
    cin>>n>>m>>r; // R行 C列 K成員 
    for(int i=0;i<n;i++)
        cin>>map[i]; //省略寫法 
    for(int i=0;i<n;i++) 
        for(int j=0;j<m;j++)
            if(map[i][j]=='.')
                for(int k=0;k<2;k++)
                    skim(i,j,k,1);
    if(r==1)
        ans/=2;//r=1時特判 
    cout<<ans<<endl;
    return 0;
}

本題遍歷每一個可以站人的點,然後利用 dfs 的思路判斷每一個點向下和向右是否能滿足條件;
之所以 r = 1 時特判,是因爲 for 循環了兩次(向右和向下)

P1149 火柴棒等式

在這裏插入圖片描述

#include<stdio.h>
int main()
{
    int a[2001]={6},b,c[10]={6,2,5,5,4,5,6,3,7,6},s=0,i,j;
    scanf("%d",&b);
    for(i=1;i<=2000;i++)
    {
            j=i;
            while(j>=1)//求每個數所用的火柴棒
            {
                    a[i]=a[i]+c[j%10];
                    j=j/10;
            }
    }
    for(i=0;i<=1000;i++)
    {
            for(j=0;j<=1000;j++) //之所以從 0開始是因爲 A+B 和 B+A 爲兩種表達式
            if(a[i]+a[j]+a[i+j]+4==b)s++;//還有加號與等號
    }
    printf("%d",s);
    return 0;
}

在這裏插入圖片描述
注意 for 循環可以到達 2000 是因爲輸入的 N 是火柴棒數 而不是 火柴棒表示的數

P3799 妖夢拼木棒

在這裏插入圖片描述

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;

int n,maxlen=-1,ans=0;
int a[100005],visited[100005];

inline int CC(int k)
{
	return ((k*k-k)/2)%mod;
}

signed main()
{
	cin>>n;
	for (int i=1;i<=n;i++) 
	{
		cin>>a[i];
		maxlen=max(maxlen,a[i]);
		visited[a[i]]++;
	}
	for (int i=1;i<=maxlen;i++)
	{
		for (int j=i;j<=maxlen;j++)
		{
			if (i==j)  ans=(ans+(CC(visited[i])*CC(visited[i+j])))%mod;
			else ans=(ans+((visited[i]*visited[j])%mod*CC(visited[i+j]))%mod)%mod;
		}
	}
	cout<<ans<<endl;
	
	return 0;
}

大概知道什麼是桶排序了
在這裏插入圖片描述
思路要挖掘開呀!滿足的不等式要找準!
因爲 a<=b,所以第二層 for 循環時從 j==i 開始
選一樣長度的木棍時用 C(x,2)==x*(x-1)/2

P2036 [COCI2008-2009#2] PERKET

在這裏插入圖片描述
在這裏插入圖片描述

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int M=15;//養成良好習慣
int a[M],b[M],n,ans=0x7f;
//ans初始化爲最大值
void dfs(int i,int x,int y){
//i是表示目前的配料編號,x爲酸度,y爲甜度
    if(i>n){
    	//注意,必須大於n才表示全部搜完
        if(x==1&&y==0)return;
        //判斷清水的情況
        ans=min(abs(x-y),ans);
        //更新ans
        return;
    }
    //分兩種情況搜索:1添加 2不添加
    dfs(i+1,x*a[i],y+b[i]);
    dfs(i+1,x,y); 
    //這題無需回溯,不明白爲何有些題解居然還用全局變量,非得回溯-_-||
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i],&b[i]);
        //讀入,用cin太慢了
    }
    dfs(1,1,0);
    printf("%d\n",ans);
    return 0;
}

簡單dfs,但我第一眼沒發現,留着下次第一眼瞧瞧

P2392 kkksc03考前臨時抱佛腳

在這裏插入圖片描述
在這裏插入圖片描述

//方法一:搜索
#include<bits/stdc++.h>
using namespace std;
int Left,Right,minn,ans;
int s[5];
int a[21][5];
void search(int x,int y){
	if(x>s[y]){
		minn=min(minn,max(Left,Right));
		return;
	}
	Left+=a[x][y];
	search(x+1,y);
	Left-=a[x][y];
	Right+=a[x][y];
	search(x+1,y);
	Right-=a[x][y];//毫無技巧的搜索回溯
}
int main(){
	cin>>s[1]>>s[2]>>s[3]>>s[4];
	for(int i=1;i<=4;i++){//減少碼量
		Left=Right=0;
		minn=19260817;
		for(int j=1;j<=s[i];j++)
			cin>>a[j][i];
		search(1,i);
		ans+=minn;
	}
	cout<<ans;
	return 0;
}

\\方法二:dp
#include<bits/stdc++.h>
using namespace std;
int a[5],i,j,k,sum,t,homework[21],dp[2501];
int main(){
	for(i=1;i<=4;i++)
		cin>>a[i];
	for(i=1;i<=4;i++){
		sum=0;	
		for(j=1;j<=a[i];j++)
			{cin>>homework[j];//輸入
			sum+=homework[j];}//總時間累加
		for(j=1;j<=a[i];j++)
			for(k=sum/2;k>=homework[j];k--)//只要是總和的一半
				dp[k]=max(dp[k],dp[k-homework[j]]+homework[j]);//01揹包
		t+=sum-dp[sum/2];//累加爲另一個腦子
		for(j=1;j<=sum/2;j++)
		dp[j]=0;//清零
	}
	cout<<t;//輸出
	return 0;
}

思路都是保證左右腦差不多題量的情況下,讓最大值儘可能的小,最後取最小的最大值

P1433 喫奶酪

壓狀dp,題解看都不想看

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