1. 程式人生 > >NOIP 2012 Day1

NOIP 2012 Day1

代碼 使用方法 一行 std 競賽 解決 但是 mark 不知道

tags:

  • NOIP
  • 模擬
  • 倍增
  • 高精
  • Python
    categories:
  • 信息學競賽
  • 總結

Luogu P1079 Vigenère 密碼

Solution

  表示並不是很懂其他人發的題解.

  我是這麽想的, 既然是題目要求用密文轉明文而且轉換規則一定的, 所以就可以用明文轉密文的逆過程來完成.

  首先要搞明白明文是怎麽變成密文的, 通過這個表可以觀察到, 如果明文的一個字符是 ch1 ,密鑰為 ch2 , 那麽密文 ch3 對應的就是 ch1 在字母表中偏移 |ch2| 位, 例如  \(\text{ch1=A,ch2=B, ch3=ch1+|ch2|=A+B-A=B}\) , 如果偏移之後超過了 ‘Z‘, 那麽就從‘A‘繼續開始, 相當於這是一個環, ‘Z‘的後面是‘A‘.

  不難發現密文是明文在字母表中進行的偏移, 那麽將密文轉換為明文只需要將這個過程反過來就好了.只需要將密文減去一個密鑰的偏移.例如 \(\text{ch3=F,ch2=C, ch1=ch3-|ch2|=F-(C-A)=D}\).

  知道了這個規則之後就不難寫出程序了, 上面如果將其進行偏移出來比\(\text{A}\)小就利用取余來處理, 具體可以看代碼

int cha=B-'A';
    return 'A'+(A-cha-'A'+26)%26;
    

還需要註意幾個問題:

  • 明文和密文對應的大小寫是一致的.
  • 最好一開始把密文和明文都變成是大寫, 這樣好轉化, 最後轉化回來.
  • \(\text{ i }\)位密文對應的密鑰為第\(\text{i}\mod \text{len2}\)位, 同樣利用取余.
  • cctype庫中幾個函數, \(\text{islower(),tolower(),isupper(),islower()}\)比較好用, 參數為一個字符.

Code

#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define N 1005
using namespace std;

char a[N],b[N];
int s,r,l;

inline
char Change(char A,char B){ int cha=B-'A'; return 'A'+(A-cha-'A'+26)%26;//將密文在字母表中進行一定偏移 } int main(){ scanf("%s%s",a,b);' r=strlen(a),l=strlen(b); int flag=0; for(int i=0;i<l;++i){ if(islower(b[i]))flag=1; if(isupper(b[i]))flag=2;//記錄一下密文一開始的大小寫 if(islower(b[i]))b[i]=toupper(b[i]);//將密文和密鑰都轉化為大寫 if(islower(a[i%r]))a[i%r]=toupper(a[i%r]); char ch=Change(b[i],a[i%r]);//得到明文的一個字符 if(flag==1)ch=tolower(ch);//再明文將其轉化為密文一開始的大小寫 if(flag==2)ch=toupper(ch); putchar(ch);//輸出這個字符 } return 0; }

Luogu P1080 國王遊戲

Solution

  首先題目我們需要對大臣進行一定的排序, 使得獲得最多獎賞的大臣獎賞最少, 前面的題解已經寫的很清楚了, 如果大臣 \(\text{a,b}\) , \(\text{a}\) 排在 \(\text{b}\) 前面的條件是 \(\text{a.left}\times \text{a.right}<\text{b.left}\times \text{b.right}\).

  那麽做法就比較顯然了, 只需要對所有人的左右手乘起來排個序就好.然後統計答案, 最頭疼的地方是需要用高精, 我自然是非常頭疼, 但是可以不用c++啊, 可以用 Python 水一波啊, 畢竟人家最擅長的就是科學運算.

  但是在用 Python 開心的寫了一波之後發現只得了60分.竟然還 WA 了一個點, 真是沒辦法忍受, 然後想方設法得到了 RE 的數據, 發現了 RE 的原因.

OverflowError: integer division result too large for a float

  百度之後發現是因為Python的浮點數是c語言float, 所以會出鍋.
然後就想自己寫一個整數除法, 先取余, 然後二分除法的結果.結果又出現了類似的問題.醉了.

  然後又百度, 好像是找到三種解決方案

  • \(\text{from \_\_future\_\_ import division}\)
  • \(\text{divmod()}\)函數
  • \(\text{decimal}\)模塊
  • \(\text{a//b}\), 等效於a整除b, 不會產生浮點運算, 但是不如第二種快, 不知道為什麽.

  可以自己百度具體的使用方法.我使用的第二種方法, 實際上\(\text{divmod(a,b)}\)返回\(\text{(int(a/b), a mod b)}\)

  在通過上述艱難過程後, 終於通過了...

Code

#表示Python的註釋
class Minister:#定義了一個類
    def __init__(self, left, right, lefttimesright):#初始化函數
            self.left = left
            self.right = right
            self.lefttimesright = lefttimesright
    def __repr__(self):
            return repr((self.left, self.right, self.lefttimesright))

n=int(input());#input()讀入一行
wang=list(map(int,input().split()));#將讀入的一行轉化為[a,b,...], []為列表list
s=[]

for i in range(0,n):
    guo=list(map(int,input().split()));
    s.append(Minister(guo[0],guo[1],guo[0]*guo[1]));

ss=sorted(s, key=lambda student: student.lefttimesright)#將排序後的結果賦值給ss
lei=wang[0]
i=0
ans=0
while i<n:
    jieguo=divmod(lei,ss[i].right)#jieguo=(a//b,a%b),jieguo[0]=a//b
    #print(jieguo[0])
    if jieguo[0]>ans:
        ans=jieguo[0];
    lei*=ss[i].left;
    i=i+1;

print(ans)#輸出

開車旅行

Solution

NOIP 2012 Day1