【D1T1vigenere密碼】
P1778vigenere密碼 Accepted 標簽:[顯示標簽]16世紀法國外交家Blaise de Vigenère設計了一種多表密碼加密算法——Vigenère密碼。Vigenère密碼的加密解密算法簡單易用,且破譯難度比較高,曾在美國南北戰爭中為南軍所廣泛使用。
在密碼學中,我們稱需要加密的信息為明文,用M表示;稱加密後的信息為密文,用C表示;而密鑰是一種參數,是將明文轉換為密文或將密文轉換為明文的算法中輸入的數據,記為k。 在Vigenère密碼中,密鑰k是一個字母串,k=k1k2…kn。當明文M=m1m2…mn時,得到的密文C=c1c2…cn,其中ci=(mi-'A'+ki-'A')mod26+'A',運算?的規則如下表所示:
Vigenere加密在操作時需要注意:
1. ?運算忽略參與運算的字母的大小寫,並保持字母在明文M中的大小寫形式;
2. 當明文M的長度大於密鑰k的長度時,將密鑰k重復使用。
輸入共2行。
第一行為一個字符串,表示密鑰k,長度不超過100,其中僅包含大小寫字母。第二行為一個字符串,表示經加密後的密文,長度不超過1000,其中僅包含大小寫字母。
輸出共1行,一個字符串,表示輸入密鑰和密文所對應的明文。
CompleteVictory Yvqgpxaimmklongnzfwpvxmniytm
Wherethereisawillthereisaway
每個測試點1s
對於100%的數據,輸入的密鑰的長度不超過100,輸入的密文的長度不超過1000,且都僅包含英文字母。
Noip2012提高組復賽D
【分析】這難道不是純模擬?不要諷刺我P的代碼啦啦啦~又臭又長。。。
【代碼】
var k,c:ansistring; kk:char; p,i,temp,now,l:longint; map:array['A'..'Z','A'..'Z'] of char; pq:longint; q1,q2,j:char; begin readln(k); k:=upcase(k); l:=length(k); readln(c); now:=1; for q1:='A' to 'Z' do begin map[q1,'A']:=q1; pq:=ord(q1); for q2:='B' to 'Z' do begin pq:=pq+1; if pq>90 then pq:=65; map[q1,q2]:=chr(pq); end; end; for i:=1 to length(c) do begin kk:=k[now]; for j:='A' to 'Z' do if map[j,kk]=upcase(c[i]) then begin if c[i] in ['A'..'Z'] then write(j) else write(chr(ord(j)+32)); end; inc(now); if now>l then now:=1; end; end.
【D1T2國王游戲】
P1779國王游戲 Accepted 標簽:[顯示標簽]恰逢H國國慶,國王邀請n位大臣來玩一個有獎游戲。首先,他讓每個大臣在左、右手上面分別寫下一個整數,國王自己也在左、右手上各寫一個整數。然後,讓這n位大臣排成一排,國王站在隊伍的最前面。排好隊後,所有的大臣都會獲得國王獎賞的若干金幣,每位大臣獲得的金幣數分別是:排在該大臣前面的所有人的左手上的數的乘積除以他自己右手上的數,然後向下取整得到的結果。
國王不希望某一個大臣獲得特別多的獎賞,所以他想請你幫他重新安排一下隊伍的順序,使得獲得獎賞最多的大臣,所獲獎賞盡可能的少。注意,國王的位置始終在隊伍的最前面。
第一行包含一個整數n,表示大臣的人數。
第二行包含兩個整數a和b,之間用一個空格隔開,分別表示國王左手和右手上的整數。接下來n行,每行包含兩個整數a和b,之間用一個空格隔開,分別表示每個大臣左手和右手上的整數。
輸出只有一行,包含一個整數,表示重新排列後的隊伍中獲獎賞最多的大臣所獲得的金幣數。
3 1 1 2 3 7 4 4 6
2
每個測試點1s
對於20%的數據,有1≤ n≤ 10,0 < a、b < 8;
對於40%的數據,有1≤ n≤20,0 < a、b < 8;
對於60%的數據,有1≤ n≤100;
對於60%的數據,保證答案不超過10^9;
對於100%的數據,有1 ≤ n ≤1,000,0 < a、b < 10000。
Noip2012提高組復賽Day1T2
【分析】以前好像不會證明,然後看題解的。現在重新做一遍,感覺真是水啊。考慮最後一個大臣,顯然他很可能是金幣最多的人。我們要讓他的金幣盡量的少。之前的大臣左手的數肯定會乘起來,所以我們要使S/A/B盡量的大。(設S是左手所有數的乘積),即讓A*B盡量的大。選完最後一個後,我們把他踢掉,然後再找一個最後的大臣。如此往復,相當於就是對A*B排序。-----當然我的證明不是很嚴謹啦。
【代碼】以前不注重長度的後果。。
ar ans,c,d,e,f:array[0..10000] of longint; a,b:array[0..1000] of longint; ansk,ck,ek,fk,x,i,j,n,t,k:longint; function da:boolean; var i:longint; begin if ek>ansk then exit(true); if ansk>ek then exit(false); for i:=ansk downto 1 do if ans[i]>e[i] then exit(false) else exit(true); end; begin readln(n); readln(a[0],b[0]); for i:=1 to n do readln(a[i],b[i]); for i:=1 to n-1 do for j:=i+1 to n do if a[i]*b[i]>a[j]*b[j] then begin t:=a[i]; a[i]:=a[j]; a[j]:=t; t:=b[i]; b[i]:=b[j]; b[j]:=t; end; ck:=1; c[ck]:=1; ansk:=0; ans[ansk]:=0; for i:=1 to n do begin fk:=0; while a[i-1]>0 do begin inc(fk); f[fk]:=a[i-1] mod 10; a[i-1]:=a[i-1] div 10; end; for j:=1 to ck do begin d[j]:=c[j]; end; fillchar(c,sizeof(c),0); for j:=1 to ck do for k:=1 to fk do c[j+k-1]:=c[j+k-1]+d[j]*f[k]; for j:=1 to ck+fk-1 do if c[j]>9 then begin c[j+1]:=c[j+1]+c[j] div 10; c[j]:=c[j] mod 10; end; ck:=ck+fk-1; while c[ck+1]>0 do begin inc(ck); c[ck+1]:=c[ck+1]+c[ck] div 10; c[ck]:=c[ck] mod 10; end; x:=0; ek:=ck; for j:=ck downto 1 do begin e[j]:=(x*10+c[j]) div b[i]; x:=(x*10+c[j]) mod b[i]; end; while (e[ek]=0) and (ek>1) do dec(ek); if da then begin ansk:=ek; for j:=1 to ansk do ans[j]:=e[j]; end; end; for i:=ansk downto 1 do write(ans[i]); end.
【D1T3開車旅行】
P1780開車旅行 Accepted 標簽:[顯示標簽】小A和小B決定利用假期外出旅行,他們將想去的城市從1到N編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市i 的海拔高度為Hi,城市i 和城市j 之間的距離d[i,j]恰好是這兩個城市海拔高度之差的絕對值,即d[i,j] = |Hi - Hj|。
旅行過程中,小A和小B輪流開車,第一天小A開車,之後每天輪換一次。他們計劃選擇一個城市S作為起點,一直向東行駛,並且最多行駛X公裡就結束旅行。小A和小B的駕駛風格不同,小B總是沿著前進方向選擇一個最近的城市作為目的地,而小A總是沿著前進方向選擇第二近的城市作為目的地(注意:本題中如果當前城市到兩個城市的距離相同,則認為離海拔低的那個城市更近)。如果其中任何一人無法按照自己的原則選擇目的城市,或者到達目的地會使行駛的總距離超出X公裡,他們就會結束旅行。
在啟程之前,小A想知道兩個問題:
1.對於一個給定的X=X0,從哪一個城市出發,小A開車行駛的路程總數與小B行駛的路程總數的比值最小(如果小B的行駛路程為0,此時的比值可視為無窮大,且兩個無窮大視為相等)。如果從多個城市出發,小A開車行駛的路程總數與小B行駛的路程總數的比值都最小,則輸出海拔最高的那個城市。
2. 對任意給定的X=Xi 和出發城市Si,小A開車行駛的路程總數以及小B行駛的路程總數。
第一行包含一個整數N,表示城市的數目。
第二行有N個整數,每兩個整數之間用一個空格隔開,依次表示城市1到城市N的海拔高度,即H1,H2,……,Hn,且每個Hi 都是不同的。
第三行包含一個整數X0。
第四行為一個整數M,表示給定M組Si和Xi。
接下來的M行,每行包含2個整數Si 和Xi,表示從城市Si 出發,最多行駛Xi 公裡。
輸出共M+1行。
第一行包含一個整數S0,表示對於給定的X0,從編號為S0的城市出發,小A開車行駛
的路程總數與小B行駛的路程總數的比值最小。
接下來的M行,每行包含2個整數,之間用一個空格隔開,依次表示在給定的Si 和Xi 下小A行駛的裡程總數和小B行駛的裡程總數。
4 2 3 1 4 3 4 1 3 2 3 3 3 4 3
1 1 1 2 0 0 0 0 0
10 4 5 6 1 2 3 7 8 9 10 7 10 1 7 2 7 3 7 4 7 5 7 6 7 7 7 8 7 9 7 10 7
2 3 2 2 4 2 1 2 4 5 1 5 1 2 1 2 0 0 0 0 0
每個測試點1s
對於30%的數據,有1≤N≤20,1≤M≤20;
對於40%的數據,有1≤N≤100,1≤M≤100;
對於50%的數據,有1≤N≤100,1≤M≤1,000;
對於70%的數據,有1≤N≤1,000,1≤M≤10,000;
對於100%的數據,有1≤N≤100,000,1≤M≤10,000,-1,000,000,000≤Hi≤1,000,000,000,0≤X0≤1,000,000,000,1≤Si≤N,0≤Xi≤1,000,000,000,數據保證Hi 互不相同。
Noip2012提高組復賽Day1T3
【分析】話說這題目真TM的拗口。我開始把A和B的操作搞反了233。
首先是拼預處理。如何快速預處理一個點之後第一個和第二個比他大的點。
以前我曾和SKYDEC做過討論的,詳見此。
之後隨便來點倍增就行了。我想法太天真,於是寫了兩端倍增。先倍增預處理出2^j後A和B分別到哪裡(顯然只要一個數組,因為奇偶性決定A還是B),再分別預處理A和B走了多少的距離。
第一問就是O(N)枚舉,找到一個最優的。第二問就直接求解了。
為了避免溢出,各種細節。調的我都快吐血了。
【代碼】
#include#include #include #include #define N 100005 #define INF 2000000000000ll using namespace std; typedef long long LL; int pos[N],H[N],first[N],second[N],w[N][18]; LL A[N][18],B[N][18],disA,disB,S; int n,i,Q,X,ans,now; double temp,Div;const double eps=1e-10; struct MM { int x,id,L,R; friend inline int operator <(const MM &A,const MM &B){return A.x 0) w[i][j]=w[w[i][j-1]][j-1]; } void Init_dis() { for (int i=1;i<=n;i++) { if (w[i][0]>0) A[i][1]=abs(H[i]-H[w[i][0]]); if (w[i][0]>0&&w[i][1]>0) B[i][1]=abs(H[w[i][0]]-H[w[i][1]]); } for (int j=2;j<=17;j++) for (int i=1;i<=n;i++) { A[i][j]=A[i][j-1]; if (w[i][j-1]>0) A[i][j]+=A[w[i][j-1]][j-1]; B[i][j]=B[i][j-1]; if (w[i][j-1]>0) B[i][j]+=B[w[i][j-1]][j-1]; } } inline void find(int start,LL cnt) { disA=disB=0; for (int i=17;i;i--) if (w[start][i]>0&&A[start][i]+B[start][i]<=cnt) { cnt-=A[start][i];cnt-=B[start][i]; disA+=A[start][i];disB+=B[start][i]; start=w[start][i]; } if (second[start]>0&&abs(H[second[start]]-H[start])<=cnt) disA+=abs(H[second[start]]-H[start]); } int main() { scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d",&a[i].x),H[i]=a[i].x,a[i].id=i; Init_order(); Init_where(); Init_dis(); scanf("%I64d",&S);ans=0;Div=INF+1; for (i=1;i<=n;i++) { find(i,S); if (disB==0) temp=INF;else temp=disA*1./disB; if (fabs(temp-Div)<=eps) {if (H[i]>H[ans]) ans=i;} else if (temp
【D2T1同余方程】
P1781同余方程 Accepted 標簽:[顯示標簽]描述
求關於x的同余方程ax ≡ 1 (mod b)的最小正整數解。
格式
輸入格式
輸入只有一行,包含兩個正整數a, b,用一個空格隔開。
輸出格式
輸出只有一行,包含一個正整數x0,即最小正整數解。輸入數據保證一定有解。
樣例1
樣例輸入1[復制]
3 10樣例輸出1[復制]
7限制
每個測試點1s
提示
對於40%的數據,2 ≤b≤ 1,000;
對於60%的數據,2 ≤b≤ 50,000,000;
對於100%的數據,2 ≤a, b≤ 2,000,000,000。來源
Noip2012提高組復賽Day2T1
【分析】簡單數論
【代碼】
var x,y,a,b,d:int64; procedure gcd(a,b:int64); var t:int64; begin if (a mod b = 0) then begin x:=0;y:=1; end else begin gcd(b,a mod b); t:=x; x:=y; y:=t-(a div b)*y; end; end; begin readln(a,b); d:=b; gcd(a,b); writeln((x mod d+d) mod d); end.
【D2T2】
P1782借教室 Accepted 標簽:[顯示標簽]描述
在大學期間,經常需要租借教室。大到院系舉辦活動,小到學習小組自習討論,都需要向學校申請借教室。教室的大小功能不同,借教室人的身份不同,借教室的手續也不一樣。
面對海量租借教室的信息,我們自然希望編程解決這個問題。我們需要處理接下來n天的借教室信息,其中第i天學校有ri個教室可供租借。共有m份訂單,每份訂單用三個正整數描述,分別為dj,sj,tj,表示某租借者需要從第sj天到第tj天租借教室(包括第sj天和第tj天),每天需要租借dj個教室。
我們假定,租借者對教室的大小、地點沒有要求。即對於每份訂單,我們只需要每天提供dj個教室,而它們具體是哪些教室,每天是否是相同的教室則不用考慮。借教室的原則是先到先得,也就是說我們要按照訂單的先後順序依次為每份訂單分配教室。如果在分配的過程中遇到一份訂單無法完全滿足,則需要停止教室的分配,通知當前申請人修改訂單。這裡的無法滿足指從第sj天到第tj天中有至少一天剩余的教室數量不足dj個。
現在我們需要知道,是否會有訂單無法完全滿足。如果有,需要通知哪一個申請人修改訂單。
格式
輸入格式
第一行包含兩個正整數n,m,表示天數和訂單的數量。
第二行包含n個正整數,其中第i個數為ri,表示第i天可用於租借的教室數量。
接下來有m行,每行包含三個正整數dj,sj,tj,表示租借的數量,租借開始、結束分別在第幾天。
每行相鄰的兩個數之間均用一個空格隔開。天數與訂單均用從1開始的整數編號。輸出格式
如果所有訂單均可滿足,則輸出只有一行,包含一個整數0。否則(訂單無法完全滿足)輸出兩行,第一行輸出一個負整數-1,第二行輸出需要修改訂單的申請人編號。
樣例1
樣例輸入1[復制]
4 3 2 5 4 3 2 1 3 3 2 4 4 2 4樣例輸出1[復制]
-1 2限制
每個測試點1s
提示
對於10%的數據,有1≤ n,m≤ 10;
對於30%的數據,有1≤ n,m≤1000;
對於70%的數據,有1≤ n,m≤ 10^5;
對於100%的數據,有1≤n,m≤10^6,0≤ri,dj≤10^9,1≤sj≤tj≤n。來源
Noip2012提高組復賽Day2T2
【分析】一眼題。但是線段樹會T。(這個用zkw貌似很麻煩?@syc1999)其實二分加判定就行了233。
不想用凌神的標號法了,直接memset水過。
【代碼】
#include#include #define N 1000005 using namespace std; int P[N],a[N],num[N],L[N],R[N],n,m,i,ans; inline int Read() { char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar()); int x=0;for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; return x; } inline int check(int D) { memset(P,0,sizeof(P)); for (int i=1;i<=D;i++) P[L[i]]-=num[i],P[R[i]+1]+=num[i]; for (int i=1;i<=n;i++) if ((P[i]+=P[i-1])+a[i]<0) return 0; return 1; } inline int erfen() { int l=1,r=m+1; while (l!=r) { int mid=(l+r)>>1; if (check(mid)) l=mid+1;else r=mid; } if (r==m+1) return 0;return r; } int main() { n=Read();m=Read(); for (i=1;i<=n;i++) a[i]=Read(); for (i=1;i<=m;i++) num[i]=Read(),L[i]=Read(),R[i]=Read(); ans=erfen(); if (ans) printf("-1\n%d",ans);else printf("0"); return 0; }
【D2T3疫情控制】
P1783疫情控制 Accepted 標簽:[顯示標簽]描述
H國有n個城市,這n個城市用n-1條雙向道路相互連通構成一棵樹,1號城市是首都,也是樹中的根節點。
H國的首都爆發了一種危害性極高的傳染病。當局為了控制疫情,不讓疫情擴散到邊境城市(葉子節點所表示的城市),決定動用軍隊在一些城市建立檢查點,使得從首都到邊境城市的每一條路徑上都至少有一個檢查點,邊境城市也可以建立檢查點。但特別要注意的是,首都是不能建立檢查點的。
現在,在H國的一些城市中已經駐扎有軍隊,且一個城市可以駐扎多個軍隊。一支軍隊可以在有道路連接的城市間移動,並在除首都以外的任意一個城市建立檢查點,且只能在一個城市建立檢查點。一支軍隊經過一條道路從一個城市移動到另一個城市所需要的時間等於道路的長度(單位:小時)。
請問最少需要多少個小時才能控制疫情。注意:不同的軍隊可以同時移動。格式
輸入格式
第一行一個整數n,表示城市個數。
接下來的n-1行,每行3個整數,u、v、w,每兩個整數之間用一個空格隔開,表示從城市u到城市v有一條長為w的道路。數據保證輸入的是一棵樹,且根節點編號為1。
接下來一行一個整數m,表示軍隊個數。
接下來一行m個整數,每兩個整數之間用一個空格隔開,分別表示這m個軍隊所駐扎的城市的編號。輸出格式
共一行,包含一個整數,表示控制疫情所需要的最少時間。如果無法控制疫情則輸出-1。
樣例1
樣例輸入1[復制]
4 1 2 1 1 3 2 3 4 3 2 2 2樣例輸出1[復制]
3限制
每個測試點2s
提示
保證軍隊不會駐扎在首都。
對於20%的數據,2≤ n≤ 10;
對於40%的數據,2 ≤n≤50,0對於60%的數據,2 ≤ n≤1000,0 對於80%的數據,2 ≤ n≤10,000;
對於100%的數據,2≤m≤n≤50,000,0來源
Noip2012提高組復賽Day2T3
【過程】這道題調到吐血。
前幾天盯上了此題。開始自己的方法連官方數據都沒過。於是開始借鑒別人的想法。網上的想法大同小異,後來我越改越混亂,越改越沒有主見。好不容易過了官方數據,VJ上WA了5個點後棄療。
一直放在那裡,今天才發現的=自己仔細想了想方法,應該完美了,開始改。
結果一陣猛調還是和前幾天的一樣。開始和網上的拍。連續找了2個代碼(都是百度搜索前幾位)都是秒拍出錯,而且= =出錯的是他們。。。於是我找來了哲教的代碼。
又是秒拍?定睛一看,哲教,呵呵。他表示無壓力改好給我。
過了一會了拍出了錯誤。激動ing:哲教,你逗我?
他表示:我知道哪裡錯了,但不屑和你這只蒟蒻說。。。
於是我又開始漫長的找其他代碼對拍。總算找到一個代碼和我飛起。。。於是立刻調大數據,5分鐘後。。。
2333,出來了!果然是我錯了!
你瞧為什麼錯了?在調用倍增的時候語句打反了。
嘻嘻,官方數據,你是有多弱啊2333。。。
【思路】最後還是自己想的2333.
二分+判定是肯定要的。
貪心的想,把所有軍隊移到1的所有兒子那裡。我們稱1的兒子為“目標點”。
先倍增預處理,求出每個軍隊是否能跑到根節點。
如果不能,那麼算出他向上跑到哪裡,在那兒打個標記。(能的等會再說)
然後dfs一遍。如果一個點的所有子節點都打上了標記,那麼它也打上標記。
這樣,我們就知道一些目標點已經不需要軍隊過去(就是已經被打上了標記的)。
之後就是貪心思想了,掃描每一個可以到根的軍隊。
如果它不能從根回到自己經過的目標點而且那個目標點需要軍隊駐扎的話,就把軍隊停在那裡。
為什麼是停在那裡呢?證明見下。
否則就把這只軍隊加入數組p,其值為它到根節點後剩下的時間。
把需要軍隊的目標點塞入數組q,其值是它與1的距離。
然後對於p和q,先排序,再從小往大匹配。
對於當前的軍隊,先判斷它走出來的目標點是否已經有軍隊了。
如果沒有的話,顯然要他去,因為他一定能去,而且目前他最沒用。
否則的話,就找一個距離最短的目標點過去(當然也可能一個都過不去喽)。
【證明】設軍隊x的經過的目標點是a,且他到根後回不到x。設他去了目標點b,設到a的軍隊是y。
顯然我們可以讓y去b,他一定能去。
【代碼】
#include#include #define INF 500000000000005ll #define N 50005 using namespace std; typedef long long LL; struct adj{int go,next,s;}a[N*2]; struct arr { int x;LL y; friend inline int operator < (const arr &A,const arr &B){return A.y =0;i--) if (f[k][i]&&dis[k][i]<=T) T-=dis[k][i],k=f[k][i]; return k; } void find(int k) { if (can[k]==Num) return;int flag=0; for (int i=end[k];i;i=a[i].next) { int go=a[i].go;if (go==f[k][0]) continue; find(go);if (can[go]!=Num) return;flag=1; } if (flag) can[k]=Num; } inline int check(LL Time) { Num++;int P=0,Q=0;p[0].y=INF; for (int i=1;i<=m;i++) if (Time Q) return 1; if (p[i].y Q; } LL erfen(LL l,LL r) { if (l==r) return l; LL mid=(l+r)>>1ll; if (check(mid)) return erfen(l,mid); return erfen(mid+1,r); } int main() { scanf("%d",&n); for (i=1;i