T1 圓圈舞蹈 題目 【題目描述】 熊大媽的奶牛在時針的帶領下,圍成了一個圈跳舞。由於沒有嚴格的教育,奶牛們之間的間隔不一致。 奶牛想知道兩隻最遠的奶牛到底隔了多遠。奶牛A到B的距離為A順時針走和逆時針走,到達B的較短路程。 告訴你相鄰個奶牛間的距離,請你告訴奶牛兩隻最遠的奶牛到底隔了多遠。 【輸入 ...
T1 圓圈舞蹈
題目
【題目描述】
熊大媽的奶牛在時針的帶領下,圍成了一個圈跳舞。由於沒有嚴格的教育,奶牛們之間的間隔不一致。
奶牛想知道兩隻最遠的奶牛到底隔了多遠。奶牛A到B的距離為A順時針走和逆時針走,到達B的較短路程。
告訴你相鄰個奶牛間的距離,請你告訴奶牛兩隻最遠的奶牛到底隔了多遠。
【輸入格式】
第一行一個整數N,表示有N只奶牛。
接下來2~N+1行,第I行有一個數,表示第I-1頭奶牛順時針到第I頭奶牛的距離。
第N+1行的數表示第N頭奶牛順時針到第1頭奶牛的距離。
【輸出格式】
一行,表示最大距離。
【數據規模】
2<=N<=100000,
1<=距離<=maxlongint,距離和<=maxlongint。
解析
分析一下題目,多試幾組數據,不難發現,其實我們並不需要知道所有牛之間的距離,
只需要知道對於每頭牛來說,離它最遠的牛有多遠,實際實現時,我們需要求出每頭牛順時針與逆時針離它最遠的牛。
這裡引用一下大佬的解釋:
如圖,對於枚舉的第一頭牛A,找到離它最遠的牛B,
當我們沿順時針枚舉第二頭牛C時,離C最遠的牛不可能是圖中紅色區域的牛了,
所以我們只需要將B沿順時針枚舉,當藍色部分的距離小於紅色部分時枚舉停止,
因為此時藍色部分的牛不可能是離C最遠的牛了。
這個演算法是沿著圈繞了一圈,時間複雜度為O(n),足以AC。
Code
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 100005; int ans, a[MAXN], b[MAXN], n, i, j, k, tot, t; int main() { //freopen("circle.in", "r", stdin); //freopen("circle.out", "w", stdout); cin >> n; for(i = 1; i <= n; i ++) scanf("%d", &a[i]); for(i = 1; i <= n; i ++) tot += a[i]; j = 2; t = a[1]; for(i = 1; i <= n; i ++) { while (min(t, tot - t) <= min(t + a[j], tot - t - a[j]) && j < n) j ++, t += a[j - 1]; ans = max(ans, min(t, tot - t)); t -= a[i]; } cout << ans << endl; //fclose(stdin); fclose(stdout); }View Code
T2 小麥畝產一千八
題目
【題目描述】
“有了金坷垃,肥料一袋能頂兩袋撒,小麥畝產一千八,吸收兩米下的氮磷鉀……”,話說HYSBZ(Hengyang School for Boys & Zy)學識淵博孩紙們一講到糧食,都會想起印度那個著名的故事:
國王要在第一個格子里放入一粒小麥,接下來的格子放入前面一個格子的兩倍的小麥。這樣所需小麥總數是巨大的,哪是不用金坷垃就能完成的任務?
不過為了減輕國王的任務,那個下棋獲勝的宰相換了一個要求:“我只需要你在棋盤外放一粒小麥,可以將其理解為第0個格子,然後你需要在第一個格子里放入若幹小麥,
之後每一個格子放入前兩個格子的小麥數之和的小麥,並且要滿足第a個格子放x粒小麥,第b個格子放……”說到這,宰相突然發現自己說的滿足第a個格子放x粒小麥的情況可能不存在……
欺君可是大罪啊!國王看到宰相遲遲不說,自己也煩了!我自己來算!於是國王拜托你,讓你算出第b個格子應該放幾粒小麥。當然,就算答案不存在,你也是要告訴國王的。
【輸入格式】
該題有多組數據,請讀到文件末結束。
對於每一組數據僅一行,3個正整數a,x,b,分別表示第a個格子放了x粒小麥,以及你所需要計算的是第b個格子的小麥數量。
【輸出格式】
對於每一次詢問,僅1個整數,為第b個格子的小麥數量,若宰相說的情況不存在,那麼請輸出-1。
【數據規模】
對於50%的數據:如果答案存在,那麼p<=50
對於100%的數據:1<=數據組數<=10000,1<=a,b<=20, 數據保證如果答案存在,那麼1<=p<=1000000.(註:p是第一格放置的小麥數)。
解析
題目明顯給出了一個拓展的斐波那契數列,其滿足:f[0]=1,f[1]=p,f[2]=p+1,f[3]=2*p+1······
而原來的斐波那契數列滿足:F[0]=1,F[1]=1,F[2]=2,F[3]=3······
設g[i]=f[i]-F[i],則g[0]=0,g[1]=p-1,g[2]=p-1,g[3]=2*p-2,g[4]=3*p-3······
輸入已經給出了f[a]=x,所以g[a]=x-F[a]=F[a-1]*(p-1),
我們先預處理出F數組,那麼每組數據我們可以O(1)計算出p,
之後遞推出答案就行了,每組數據時間複雜度為O(b)。
Code
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> using namespace std; int a, b; long long f[30], x; inline void check(int mid) { f[1] = mid; for(int i = 2; i <= a; i ++) f[i] = f[i - 1] + f[i - 2]; } inline void getans(int mid) { f[1] = mid; for(int i = 2; i <= b; i ++) f[i] = f[i - 1] + f[i - 2]; printf("%lld\n", f[b]); } int main() { //freopen("kela.in", "r", stdin); //freopen("kela.out", "w", stdout);return 0; f[0] = 1; while (scanf("%d%lld%d", &a, &x, &b) != EOF) { int l = 1, r = 1000000; while (l != r - 1) { int mid = (l + r) >> 1; check(mid); if (f[a] > x) r = mid; else l = mid; } check(l); if (f[a] == x) getans(l); else { check(r); if (f[a] == x) getans(r); else printf("-1\n"); } } //fclose(stdin); fclose(stdout); }View Code
T3 好元素
題目
【題目描述】
小A一直認為,如果在一個由N個整數組成的數列{An}中,存在以下情況:
Am+An+Ap = Ai (1 <= m, n, p < i <= N , m,n,p可以相同),那麼Ai就是一個好元素。
現在小A有一個數列,請你計算數列中好元素的數目。
【輸入格式】
第一行只有一個正整數N,意義如上。
第二行包含N個整數,表示數列{An}。
【輸出格式】
輸出一個整數,表示這個數列中好元素的個數。
【數據規模】
對於10%的數據1<=N<=10
對於40%的數據1<=N<=500 -10^5<=Ai<=10^5
對於70%的數據1<=N<=5000 -10^6<=Ai<=10^6
對於100%的數據1<=N<=5000 -10^9<=Ai<=10^9
解析
10分做法:四層迴圈枚舉a[i],a[m],a[n],a[p],時間複雜度O(n4)
40分做法:bool數組存儲a[i],再三層迴圈a[m],a[n],a[p],若a[i]存在個數就+1,時間複雜度O(n3)
70分做法:我們發現40分做法計算三數和用了O(n3),而查詢a[i]只用了O(n),
我們把代數式轉換為a[m]+a[n]=a[i]-a[p],這樣計算和查詢都是O(n2),總時間複雜度為O(n2)
100分做法:在70分演算法的前提下加上哈希進行判斷即可。
Code
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<string> #include<cmath> #include<ctime> #include<queue> #include<stack> #include<map> #include<set> using namespace std; const int MAXN=int(5e3)+3; const int MAXH=int(1e7)+int(3e6); const int Hash_Value=33554431; const int MAXV=Hash_Value+1; int Top,Val[MAXH],Next[MAXH],First[MAXV]; int N,Ans,A[MAXN]; void Push_Hash(const int &x) { int Px=x&Hash_Value; Next[++Top]=First[Px]; Val[Top]=x; First[Px]=Top; return ; } bool Ask_Hash(const int &x) { int Px=x&Hash_Value; for (int k=First[Px];k!=0;k=Next[k]) if (Val[k]==x) return true; return false; } int Get() { int Sign=0,Num=0; char ch; for (ch=getchar();ch<'0'||ch>'9';ch=getchar()) if (ch=='-') break; ch=='-'?Sign=1:Num=ch-48; for (ch=getchar();ch>='0'&&ch<='9';ch=getchar()) Num=Num*10+ch-48; return Sign==0?Num:-Num; } int main() { //freopen("good.in","r",stdin); //freopen("good.out","w",stdout); N=Get(); for (int i=1;i<=N;++i) { A[i]=Get(); for (int j=i-1;j>=1;--j) { int Now=A[i]-A[j]; if (Ask_Hash(Now)) { ++Ans; break; } } for (int j=1;j<=i;++j) { int Now=A[i]+A[j]; Push_Hash(Now); } } printf("%d\n",Ans); //fclose(stdin);fclose(stdout); return 0; }View Code
T4 國際象棋
題目
【題目描述】
小口口不是一個普通青年,所以他不喜歡玩普通國際象棋。他喜歡玩的國際象棋是這樣的:把兩個邊長分別為 N*N 和 M*M 的國際象棋盤拼在一起。就像這樣:
現在小口口又來刁難你了:他告訴你 N,M,W,H 以及 K。
然後問你這樣的棋盤上放 K 個城堡互相不攻擊有多少種方案。
城堡的攻擊範圍是一整行和一整列。
【輸入格式】
第一行,五個整數,分別為 N,M,W,H,K。
【輸出格式】
輸出一行一個整數表示方案總數。
【數據規模】
10%的數據N=M=K.
50%的數據W=H=0,1<=N,M<=15(包括上述的10%的數據).
100%的數據N,M<=20,W,H,K<=10^9.
解析
本蒟蒻表示,這題神馬不會寫,隨便寫了個暴力就溜了。
So,直接拋出巨佬題解:
Code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int n,m,w,h,k,W,H; struct ff { int len,a[50]; ff(){ len=0; memset(a,0,sizeof(a)); } inline ff operator *(const int &b){ ff c=*this; for (int i=1; i<=len; ++i) c.a[i]*=b; for (int i=1; i<=len; ++i){ c.a[i+1]+=c.a[i]/10; c.a[i]%=10; } c.len=len; while (c.a[c.len+1]) c.len++, c.a[c.len+1]=c.a[c.len]/10, c.a[c.len]%=10; return c; } inline void operator +=(const ff &b){ len=max(len,b.len); for (int i=1; i<=len; ++i){ a[i]+=b.a[i]; a[i+1]+=a[i]/10; a[i]%=10; } while (a[len+1]) ++len, a[len+1]=a[len]/10, a[len]%=10; } }f[45][25][25][25],ans; void PRT(ff a) { for (int i=a.len; i; --i) printf("%d",a.a[i]); printf("\n"); } bool check(int x,int y) { if (x<=n && y<=n) return 1; if (x>w && x<=w+m && y>h && y<=h+m) return 1; return 0; } void work() { if (w>=n) w=n; if (h>=n) h=n; if (m+w<=n && m+h<=n) w=h=0,m=n; int H=max(h+m,n),W=max(m+w,n); //H!W! int l1=w,l2=min(w+m,n),l3=max(w+m,n); int n1=l1,n2=l2-l1,n3=l3-l2; f[0][0][0][0].len=1; f[0][0][0][0].a[1]=1; for (int i=0; i<H; ++i){ for (int x=0; x<=n1; ++x) if (x<=k){ for (int y=0; y<=n2; ++y) if (x+y<=k) for (int z=0; z<=n3; ++z) if (x+y+z<=k){ if (check(l1,i+1)){ f[i+1][x+1][y][z]+=f[i][x][y][z]*(n1-x); } if (check(l3,i+1)) f[i+1][x][y][z+1]+=f[i][x][y][z]*(n3-z); if (check(l2,i+1)) f[i+1][x][y+1][z]+=f[i][x][y][z]*(n2-y); f[i+1][x][y][z]+=f[i][x][y][z]; } } } for (int x=0; x<=n1; ++x) for (int y=0; y<=n2; ++y) for (int z=0; z<=n3; ++z) if (x+y+z==k){ ans+=f[H][x][y][z]; } for (int i=ans.len; i; --i) printf("%d",ans.a[i]); } int main() { //freopen("chess.in","r",stdin); //freopen("chess.out","w",stdout); scanf("%d%d%d%d%d",&n,&m,&w,&h,&k); work(); //fclose(stdin); fclose(stdout); }View Code