目錄:
T1:找路
T2:家庭作業
T3:算法學習
T4:友好數對
正題:
T1:找路
題目描述
Mirko 剛開始學車,因此他還不會在一個很狹窄的地方掉頭,所以他想找一個不需要掉頭的地方學車。Mirko馬上發現他想找的地方必須沒有死衚衕,因爲死衚衕是不可能出來的,除非掉頭(假設Mirko也不會倒車)。現在,你需要寫一個程序,來分析一個地方的地圖,研究是否這個地方適合Mirko練習開車。
這張地圖是包含R*C個單元格的,單元格中的“X”代表一個建築物,單元格中的“.”代表路面。從一個路面單元格,Mirko可以向旁邊上下左右四個方向的單元格開去,只要開過去的地方同樣也是路面。
最後,我們要得出這個地圖是否包含死衚衕,假如從任意一個路面單元格出發,沿着任何一個可以行駛的方向,我們可以不用掉頭就能返回到出發點,那麼這個地圖就是沒有死衚衕的。
輸入
第一行包括兩個整數R和C(3<=R,C<=10),表示這個地圖的大小。
接下來R行,每行有C個字符,每個字符可能是“X”和“.”。地圖中至少有兩個路面單元格,並且所有的路面都是相連的(相互可達的)。
輸出
輸出只有一行,輸出0表示這個地圖沒有死衚衕,輸出1表示這個地圖存在死衚衕。
分析:
這道題很簡單。
就是遍歷整個地圖,如果有一個點四周是‘.’,就計數。
如果有<2個這樣的點,就說明沒有死衚衕。
CODE:
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
using namespace std;
char a[12][12];
int m,n;
bool f=true;
int main()
{
freopen("okret.in","r",stdin);
freopen("okret.out","w",stdout);
memset(a,'X',sizeof(a));
scanf("%d%d",&m,&n);
for (int i=1;i<=m;i++)
{
for (int j=1;j<=n;j++)
{
scanf(" %c",&a[i][j]); //讀入
}
}
for (int i=1;i<=m;i++)
{
for (int j=1;j<=n;j++)
{
int t=0; //計數器
if (a[i][j]=='X') continue; //不是'.'
if (a[i-1][j]=='.') t++;
if (a[i][j-1]=='.') t++;
if (a[i+1][j]=='.') t++; //判斷上下左右
if (a[i][j+1]=='.') t++;
if (t<2) //小於2個
{
f=false;
}
}
}
if (f) printf("0"); //沒有死衚衕
else printf("1"); //有死衚衕
}
T2:家庭作業
題目描述
Mirko最近收到了一個家庭作業,作業的任務是計算兩個數A和B的最大公約數。由於這兩個數太大了,我們給出了N個數,他們的乘積是A,給出M個數,他們的乘積是B。
Mirko想要驗算自己的答案,所以他想找你寫一個程序來解決這個問題。如果這個最大公約數超過了9位數,那麼只需要輸出最後9位就可以了。
輸入
第一行包含一個正整數N,範圍是1到1000。第二行是N個用空格隔開的正整數(小於10億),他們的乘積是A。第三行包含一個正整數M,範圍是1到1000。第四行是M個用空格隔開的正整數(小於10億),他們的乘積是B。
輸出
輸出有且只有一行,表示A和B的最大公約數,如果結果超過了9位數,輸出最後9位數就可以了。
分析:
這道題要求最大公約數。
如果最大公約數>題目要求,做個標記,最後判斷一下,printf("%09ld",ans),就是輸出後9位。
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
int n,m;
LL k,ans=1,a[1001],x,f;
int euclid(int y,int x)
{
if(x==0) return y; //求最大公約數函數
return euclid(x,y%x);
}
int main(){
//freopen("zadaca.in","r",stdin);
//freopen("zadaca.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
scanf("%lld",&x);
for(int j=1; j<=n; j++)
{
k=euclid(a[j],x); //找兩個數列中的最大公約數
if(ans*k>=1000000000)
f=1; //標記
ans=ans*k%1000000000; //取後9位
a[j]/=k;
x/=k;
}
}
if(f==1) //有標記
printf("%09ld",ans); //輸出後9位
else
printf("%lld",ans);
}
T3:算法學習
題目描述
自從學習了動態規劃後,Famer KXP對動態規劃的熱愛便一發不可收拾,每天都想找點題做,一天,他找到了一道題,但是不會做,於是,他找到了你。題目如下:
給出N個無序不重複的數,再有M個詢問,每次詢問一個數是否在那N個數中,若在,則ans增加2^K,K爲該數在原數列中的位置。
由於ans過大,所以只要求你輸出ans mod 10^9+7。
輸入
第一行,兩個數N,M,第二行N個數,第三行M個數。
輸出
輸出最終答案。
樣例輸入
5 5
1 3 4 6 5
1 8 1 3 6
樣例輸出
24
分析:
很多做法。
一種正解爲二分查找+快速冪。
兩個函數打好後帶到主函數就ok。
CODE:
#include <iostream>
#include <cstdio>
using namespace std;
long long k,n,m,ans,z,a[100001],b[100001],c[100001];
void fast(long long l,long long r)
{ //快排
if (l>=r) return;
int i=l,j=r;
long long mid=a[(l+r)/2];
do
{
while(a[i]<mid) i++;
while(a[j]>mid) j--;
if(i<=j)
{
a[0]=a[i];a[i]=a[j];a[j]=a[0];
b[0]=b[i];b[i]=b[j];b[j]=b[0];
i++;j--;
}
}
while(i<=j);
fast(l,j);
fast(i,r);
}
int search_(long long x,long long y)
{ //二分查找
int m=x+(y-x)/2;
if(a[m]==k)
return m;
if(a[m]>k)
return search_(x,m-1);
if(a[m]<k)
return search_(m+1,y);
}
int main()
{
freopen("sfxx.in","r",stdin);
freopen("sfxx.out","w",stdout);
cin>>n>>m;
b[0]=1;
for(int i=1; i<=n; i++)
{
cin>>a[i];
b[i]=(b[i-1]*2)%1000000007;
}
fast(1,n);
for(int i=1; i<=m; i++)
{
cin>>k;
if((k>=a[1])&&(k<=a[n]))
{
ans=(ans+b[search_(1,n)])%1000000007; //帶入再%
}
}
cout<<ans<<endl;
}
T4:友好數對
題目描述
在順利完成家庭作業以後,Mirko感到非常的厭倦。所以,他列出了N個數,這些數中有些數對他是喜歡的,有些數對他是不喜歡的。
他喜歡的數對叫做友好數對,如果兩個數至少有一個相同的數字(不要求在相同的位置),那麼這兩個數就是友好數對。請幫助Mirko在這N個數找出有多少友好數對。
輸入
第一行一個正整數N(1<=N<=1000000)。
接下來N行,每行一個正整數,範圍在1到1018之間。N個數中任意兩個數都是不同的。
輸出
只有一行一個整數,表示友好數對的個數。
分析:
剛看這道題,感覺不可做 。
聽完我們學校一位dalao的講解後,得:
先把輸入的數在二進制下判斷兩個數有沒有相同一位都爲1,也就是都有一個相同的數,然後標記當前位,最後判斷合法,累加答案。
CODE:
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
LL ans,b[10001];
LL i,n,t,s,j,k,x;
int main(){
//freopen("kompici.in","r",stdin);
//freopen("kompici.out","w",stdout);
scanf("%lld",&n);
for(i=1;i<=n;i++)
{
t=0;s=0;
scanf("%lld",&x);
while(x>0)
{
t=x%10;
x=x/10;
s=s|(1<<t); //或運算+位運算判斷哪一位相同
}
b[s]++; //相同的位標記
}
for(i=1;i<=1023;i++)
{
if(b[i]==0) continue; //沒有標記
for(j=1;j<=1023;j++)
{
if((i&j)==0/*沒有一位相同*/||b[j]==0||i==j) continue; //都是不合法條件
ans=ans+b[i]*b[j];
}
ans=ans+b[i]*(b[i]-1);
}
ans=ans/2; //最後 div 2
cout<<ans;
return 0;
}