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,题解看都不想看