深基刷题记录(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,题解看都不想看

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