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