大提琴的聲音就像一條河,左岸是我無法忘卻的回憶,右岸是我值得緊握的璀璨年華,中間流淌的,是我年年歲歲淡淡的感傷。
李白打酒
話說大詩人李白,一生好飲,幸好他從不開車。
一天,他提着酒壺,從家裏出來,酒壺中有酒 2 鬥,他邊走邊唱:
無事街上走,提壺去打酒。
逢店加一倍,遇花喝一斗。
這一路上,他一共遇到店 mm 次,遇到花 nn 次,已知最後一次遇到的是花,他正好把酒喝光了。
請你計算李白遇到店和花的次序,可以把遇店記爲 aa,遇花記爲 bb。
例如:這一路上,他一共遇到店 55 次,遇到花 1010 次,已知最後一次遇到的是花,他正好把酒喝光了。則:babaabbabbabbbb 就是合理的次序。像這樣的答案一共有多少呢?請你計算出所有可能方案的個數(包含題目給出的)。
Input
輸入一個整數 TT,包括 TT 組數據,每組數據包括遇到店的次數 mm,花的次數 nn。
Output
對於每組數據,輸出李白遇到店和花的可能次序的個數。
Example
input
Copy
1 5 10
output
Copy
14
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <cctype>
#include <bitset>
#include <utility>
#include <sstream>
#include <complex>
#include <iomanip>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int ct,T,m,n;
void dfs(int sum,int fg,int store,int flower)
{
if(store==0&&flower==0&&fg==1)//最後一次遇到的是花
{
if(sum==0)//恰好把酒喝光
{
ct++;
return ;
}
else
return ;
}
else
{
if(store>0&&sum>0)//有酒經過商店
dfs(sum*2,0,store-1,flower);
if(flower>0&&sum>0)//有酒經過花店
dfs(sum-1,1,store,flower-1);
}
}
int main()
{
cin>>T;
while(T--)
{
ct=0;
cin>>m>>n;
dfs(2,0,m,n);
cout<<ct<<endl;
}
return 0;
}
九宮重排
如下面第一個圖的九宮格中,放着 1 到 8 的數字卡片,還有一個格子空着。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。
我們把第一個圖的局面記爲:12345678.
把第二個圖的局面記爲:123.46758
顯然是按從上到下,從左到右的順序記錄數字,空格記爲句點。
本題目的任務是已知九宮的初態和終態,求最少經過多少步的移動可以到達。如果無論多少步都無法到達,則輸出 −1−1。
Input
輸入第一行包含九宮的初態,第二行包含九宮的終態。
Output
輸出最少的步數,如果不存在方案,則輸出 −1−1。
Example
input
Copy
12345678. 123.46758
output
Copy
3
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <cctype>
#include <bitset>
#include <utility>
#include <sstream>
#include <complex>
#include <iomanip>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int fx[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
int jc[]= {1,1,2,6,24,120,720,5040,40320,362880}; //表示階乘運算的結果
int vis[4000010];
struct node
{
int now[10];
int x;
int bs;
} ks,mb,p;
queue<node> Q;
int cantor(int *s)
{
int i,j,num=0,temp;
for(i=0; i<9; i++)
{
temp=0;//temp記錄當前數位前面的低數位中小於當前位數上的數字的個數
for(j=i+1; j<9; j++)
if(s[j]<s[i])
temp++;
num+=jc[9-1-i]*temp;//乘以相應的階乘
}
return num;
}
void bfs()
{
int t,g=cantor(mb.now);
Q.push(ks);
vis[cantor(ks.now)]=1;
while(!Q.empty())
{
p=Q.front();
if(cantor(p.now)==g)
{
printf("%d\n",p.bs);
return;
}
int x=p.x/3,y=p.x%3;
for(int i=0; i<4; i++)
{
int x0=x+fx[i][0];
int y0=y+fx[i][1];
if (x0<0||x0>2||y0<0||y0>2)
continue;
node q=p;
q.x=x0*3+y0;
q.bs++;
q.now[p.x]=q.now[q.x];
q.now[q.x]=0;
t=cantor(q.now);
if(!vis[t])
{
vis[t]=1;
Q.push(q);
}
}
Q.pop();
}
printf("-1\n");
}
兩點
福克斯在玩一款手機解迷遊戲,這個遊戲叫做"兩點"。基礎級別的時候是在一個 n×mn×m 單元上玩的。像這樣:
每一個單元有包含一個有色點。我們將用不同的大寫字母來表示不同的顏色。
這個遊戲的關鍵是要找出一個包含同一顏色的環。看上圖中 44 個藍點,形成了一個環。一般的,我們將一個序列 d1,d2,...,dkd1,d2,...,dk 看成一個環,當且僅當它符合下列條件時:
1. 這 kk 個點不一樣,即當 i≠ji≠j 時,didi 和 djdj 不同。
2. kk 至少是 44。
3. 所有的點是同一種顏色。
4. 對於所有的 1≤i≤k−11≤i≤k−1: didi 和 di+1di+1 是相鄰的。還有 dkdk 和 d1d1 也應該相鄰。單元 xx 和單元 yy 是相鄰的當且僅當他們有公共邊。
當給出一幅格點時,請確定裏面是否有環。
Input
單組測試數據。
第一行包含兩個整數 nn 和 mm (2≤n,m≤50)(2≤n,m≤50): 板子的行和列。
接下來 nn 行,每行包含一個有 mm 個字母的串,表示當前行每一個點的顏色。每一個字母都是大寫字母。
Output
如果有環輸出 Yes,否則輸出 No。
Example
input
Copy
3 4 AAAA ABCA AADA
output
Copy
No
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <cctype>
#include <bitset>
#include <utility>
#include <sstream>
#include <complex>
#include <iomanip>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
char mp[60][60];
int vis[60][60],fg,n, m;
int fx[] = {0, -1, 0, 1};
int fy[] = {1, 0, -1, 0};
void dfx(int x, int y, char c, int dir)
{
if(x < 0 || x > n-1 || y < 0 || y > m-1 || mp[x][y] != c)
return;
if(vis[x][y])
{
fg = 1;
return;
}
vis[x][y] = 1;
for(int i = 0; i < 4; i++)
{
if(dir == 0 && i == 2)
continue;
if(dir == 1 && i == 3)
continue;
if(dir == 2 && i == 0)
continue;
if(dir == 3 && i == 1)
continue;
int xx = x + fx[i];
int yy = y + fy[i];
dfx(xx, yy, c, i);
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++)
scanf("%s", mp[i]);
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(fg)
break;
if(vis[i][j])
continue;
dfx(i, j, mp[i][j], -1);
}
if(fg)
break;
}
if(fg)
printf("Yes\n");
else
printf("No\n");
return 0;
}
大臣的旅費
很久以前,T 王國空前繁榮。爲了更好地管理國家,王國修建了大量的快速路,用於連接首都和王國內的各大城市。
爲節省經費,T 國的大臣們經過思考,制定了一套優秀的修建方案,使得任何一個大城市都能從首都直接或者通過其他大城市間接到達。同時,如果不重複經過大城市,從首都到達每個大城市的方案都是唯一的。
J 是 T 國重要大臣,他巡查於各大城市之間,體察民情。所以,從一個城市馬不停蹄地到另一個城市成了 J 最常做的事情。他有一個錢袋,用於存放往來城市間的路費。
聰明的 J 發現,如果不在某個城市停下來修整,在連續行進過程中,他所花的路費與他已走過的距離有關,在走第 xx 千米到第 x+1x+1 千米這一千米中(xx 是整數),他花費的路費是 x+10x+10 這麼多。也就是說走 11 千米花費 1111,走 22 千米要花費 2323。
J 大臣想知道:他從某一個城市出發,中間不休息,到達另一個城市,所有可能花費的路費中最多是多少呢?
Input
輸入的第一行包含一個整數 nn (0<n<20)(0<n<20),表示包括首都在內的 T 王國的城市數
城市從 1 開始依次編號,1 號城市爲首都
接下來 n−1n−1 行,描述 T 國的高速路(T 國的高速路一定是 n−1n−1 條)
每行三個整數 Pi,Qi,DiPi,Qi,Di,表示城市 PiPi 和城市 QiQi 之間有一條高速路,長度爲 DiDi 千米 (0<Di<100)(0<Di<100)
Output
輸出一個整數,表示大臣 J 最多花費的路費是多少
Example
input
Copy
5 1 2 2 1 3 1 2 4 5 2 5 4
output
Copy
135
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <cctype>
#include <bitset>
#include <utility>
#include <sstream>
#include <complex>
#include <iomanip>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int mp[30][30],n,P,Q,D,sum;
int main()
{
cin>>n;
int ls=n-1;
memset(mp,inf,sizeof(mp));
while(ls--)
{
cin>>P>>Q>>D;
mp[P][Q]=mp[Q][P]=D;
}
for(int k=1; k<=n; k++)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(mp[i][k]!=inf&&mp[k][j]!=inf)
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
}
}
}
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
sum=max(sum,mp[i][j]);
cout<<sum*(sum+1)/2+sum*10<<endl;
return 0;
}
Tri Tiling
In how many ways can you tile a 3×n3×n rectangle with 2×12×1 dominoes? Here is a sample tiling of a 3×123×12 rectangle.
Input
Input consists of several test cases followed by a line containing −1−1. Each test case is a line containing an integer 0≤n≤300≤n≤30.
Output
For each test case, output one integer number giving the number of possible tilings.
Example
input
Copy
0 6 10 -1
output
Copy
1 41 571
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <cctype>
#include <bitset>
#include <utility>
#include <sstream>
#include <complex>
#include <iomanip>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int dp[50],n;
int main()
{
dp[0]=1;
dp[2]=3;
for(int i=4; i<=30; i++)
dp[i]=4*dp[i-2]-dp[i-4];
while(cin>>n&&n!=-1)
{
cout<<dp[n]<<endl;
}
return 0;
}
01 組成的 N 的倍數
output
standard output
給定一個自然數 N,找出一個 M,使得M>0 且 M 是 N 的倍數,並且 M 的 10 進製表示只包含 0 或 1,求最小的 M。
Input
輸入 1個數 N。(1≤N≤106)(1≤N≤106)
Output
輸出符合條件的最小的 M。
Examples
input
Copy
1
output
Copy
1
input
Copy
4
output
Copy
100
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <ctime>
#include <cctype>
#include <bitset>
#include <utility>
#include <sstream>
#include <complex>
#include <iomanip>
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
struct node
{
int x;
int q;
} p[5000010];
int vis[5000010],n,ct;//vis餘數狀態0未出現,1出現
void dfs(int y)
{
int ans=p[y].q;
if(ans<=0)
{
cout<<1;
return;
}
dfs(ans);
cout<<p[ans].x;
return;
}
void bfs()
{
ct=1;
memset(vis,0,sizeof(vis));
node ls1,ls2;
ls1.x=1,ls1.q=0;
queue<node> qu;
p[0].x=1;
p[0].q=0;
qu.push(ls1);
while(!qu.empty())
{
ls2=qu.front();
qu.pop();
for(int i=0; i<=1; i++)
{
ls1.x=ls2.x*10+i;
ls1.x%=n;//餘數
if(!vis[ls1.x])
{
ls1.q=ct;
vis[ls1.x]=1;
p[ct].x=i;
p[ct].q=ls2.q;
qu.push(ls1);
if(ls1.x==0)
{
dfs(ct);
cout<<i<<endl;
return;
}
ct++;
}
}
}
}
int main()
{
cin>>n;
if(n==1)
cout<<1<<endl;
else
bfs();
return 0;
}
剪格子
如下圖所示,3×33×3 的格子中填寫了一些整數。
我們沿着圖中的星號線剪開,得到兩個部分,每個部分的數字和都是 6060。
本題的要求就是請你編程判定:對給定的 m×nm×n 的格子中的整數,是否可以分割爲兩個部分,使得這兩個區域的數字和相等。
如果存在多種解答,請輸出包含左上角格子的那個區域包含的格子的最小數目。
如果無法分割,則輸出 00。
Input
程序先讀入兩個整數 m,nm,n 用空格分割 (m,n<10)(m,n<10),表示表格的寬度和高度。
接下來是 mm 行,每行 nn 個正整數,用空格分開。每個整數不大於 1000010000。
Output
輸出一個整數,表示在所有解中,包含左上角的分割區可能包含的最小的格子數目。
Example
input
Copy
3 3 10 1 52 20 30 1 1 2 3
output
Copy
3
題解:
題目大體意思是要分成兩部分,這兩部分數字的和要相等。
背後的意思是 怎麼分成兩部分。
正常思路是 dfs 上下左右,左上角所在集合標記成 1,一旦標記集合的和是總和的一半,此時實現了 “分開”。在每次“分開”中更新最小的塊數。
問題來了。(假設陰影處是最優解)
所以 考慮添加方向
變成 8 個方向
int dir[8][2] = {1, 0, 1, -1, 0, 1, 0, -1, -1, 0, -1, 1, 1, 1, -1, -1};
上下左右,左上 左下 右上 右下
但是會有很多組數據超時
最後考慮,斜着的方向只添加一個,左下(從 0, 0 處劃分兩塊,大體方向是左下,下,右下)
int dx[] = {0, 0, 1, -1, 1};
int dy[] = {1, -1, 0, 0, -1};
又出現新問題了
左下角的沒有辦法剪,所以說:
雖然這種情況可以搜索到,但是這種情況不是解。
怎麼排除這種情況呢
被標記的小塊的,看看周圍有沒有提前被標記了的就行了。(上下左右是否接壤)
左下角的上面和右面都沒有接壤,所以沒有辦法剪下來,所以排除。
大體思路就是這樣
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int n, m;
int ans = INF;
int e[20][20];
int sum; //總和
int dx[] = {0, 0, 1, -1, 1};
int dy[] = {1, -1, 0, 0, -1};
bool vis[20][20];
bool check() { // 檢查有沒有斜着蹦出來的
int flag = 0;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
if (vis[i][j]) { // 看看所有被標記點 是不是有斜着的
flag = 1;
int k = 0;
for (k = 0; k < 4; k++) {
if (i + dx[k] < 0 || i + dx[k] >= m || j + dy[k] < 0 ||
j + dy[k] >= n)
continue; // 界外
if (vis[i + dx[k]]
[j + dy[k]]) { // 試探: i+dx[k] j+dy[k]
// (上下左右被標記 ) 就跳出
flag = 0;
break; //說明它的上下左右至少有一個接壤的
//也就是說不能出現斜着蹦出來的
}
}
if (flag)
return false;
}
}
return true;
}
void dfs(int x, int y, int res, int step) { // x,y 標記的和,標記了多少塊
if (res > sum / 2)
return;
if (res == sum / 2 && check()) {
ans = min(ans, step);
return;
}
for (int i = 0; i <= 4; i++) {
int xx = x + dx[i];
int yy = y + dy[i];
if (xx >= m || yy >= n || xx < 0 || yy < 0)
continue; // 界外
if (!vis[xx][yy]) {
vis[xx][yy] = 1;
dfs(xx, yy, res + e[xx][yy], step + 1);
vis[xx][yy] = 0;
}
}
}
int main() {
scanf("%d%d", &m, &n);
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
scanf("%d", &e[i][j]), sum += e[i][j];
if (sum & 1) {
printf("0\n");
return 0;
}
vis[0][0] = 1;
dfs(0, 0, e[0][0], 1);
if (ans == INF)
printf("0\n");
else
printf("%d\n", ans);
return 0;
}