[OI模擬賽]2017.8.24 Day5
A題 第K小的和
Tom有n個數字Ai,每個數字都不?一樣。現在,Tom想把這些數字次數的選擇,然後 把選定的數字求和,例如: Tom有2個數字,這2個數字分別是:3,5,那麽,他能夠組成的數字有: 3,5,6,8,9,10,11,12… 現在,他好奇組成的和中,第k?小的是多少,你能告訴他麽?
輸?入格式: 第?一?行兩個正整數n,k表?示Tom?手上數字的個數,以及要求的是第?幾?小的數字。 第?二?行n個正整數Ai,表?示Tom?手上每個數字的值。
輸出格式: ?一個正整數,表?示第k?小的數是多少。
輸?入/輸出樣例:
kth.in:
2 8
3 5
kth.out: 8
30%數據:保證ans<=100,00060%數據:k<=100,000
100%數據:k<=100,000,000
100%數據:n<=100,每個數字<=1000,答案在64位整數範圍內且gcd(Ai)=1。
思考:
看到GCD(Ai)=1 我就開始猜這是一道數學題目了,在我的無限亂搞之下發現數字必定會在某個點之後連續即從n點之後到之後任意一個數都可以到達。
但是這個n點非常難找,我繼續猜我的瞎結論 n點必定於最小的兩個Ai有關 在搞了幾組數據看了之後發現,的確如此,n點在Ai*Ai+1*gcd(Ai,Ai+1)之前 Ai和Ai+1表示最小的兩個數
怎麽證明呢?(抱歉我不會,我只是和暴力程序對拍了100多組數據。)
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> #define go(i,a,b) for(register int i =a;i<=b;i++) #define ro(i,a,b) for(register int i =a;i>=b;i--) using namespace std; #define LL long long int n; LL a[105]; priority_queue<LL,vector<LL>,greater<LL> > q; LL k; bool book[100000005]; int main() { freopen("kth.in","r",stdin); freopen("kth.out","w",stdout); cin>>n>>k; int minn,subn; int flag=0; int num=0; go(i,1,n) { cin>>a[i]; if(book[a[i]]==0) { q.push(a[i]);book[a[i]]=1;num++; } if(a[i]==1) flag=1; } LL tt=0; if(flag==1) { cout<<k<<endl; return 0; } if(num==1) { cout<<a[1]*k<<endl; return 0; } int duandian=0; minn=q.top(); q.pop(); subn=q.top(); q.push(minn); //cout<<minn<<‘ ‘<<subn<<endl; int chen=minn*subn*__gcd(minn,subn); while (!q.empty() && tt!=k-1 ) { tt++; LL now=q.top(); if(now>=chen) { duandian=now; break; } go(i,1,n) { LL p=now+a[i]; if(book[p]==0) { q.push(p);book[p]=1; } } q.pop(); } LL ans=duandian+(k-tt); if(k!=tt+1) cout<<ans<<endl; else cout<<q.top()<<endl; }
B題 消磚塊
遊戲畫?面是由?一個N*M的磚塊矩陣構成的,每個磚塊有?一種顏?色。兩個磚塊相鄰當 且僅當他們在上、下、左、右四個?方向上相鄰。?白?色磚塊是遊戲中特有的磚塊,可以當 做任何?一個顏?色。 遊戲的過程是這樣的:點擊任何?一個有磚塊的位置,如果該磚塊與其他和它顏?色相 同的磚塊構成的連通塊中,磚塊的個數?大於等於1個,則將這些磚塊全部消掉,消掉後, 上?方的磚塊?首先下落,下落後整列向左平移直到所有空?白列都在右邊為?止。
以下是?一個掉落的情況,消除顏?色2,?首先其他磚塊掉落,然後平移:
1 1 2 3 ——》 1 0 0 0 ——》 1 0 0 0
1 2 2 3 ——》 1 0 0 3 ——》 1 0 3 0
1 2 2 2 ——》 1 1 0 3 ——》 1 1 3 0
我們的問題很簡單:對於?一個給定的遊戲局?面,最少需要消除?幾次能夠使所有磚塊 都消完呢?(數據中沒有?白?色磚塊)
輸?入格式: 第?一?行兩個整數n,m,表?示矩陣的尺?寸。 之後n?行m列,表?示每個位置的顏?色。 輸出格式: ?一個整數,表?示最少的消除次數,題??目保證有解。
輸?入/輸出樣例: game.in: 3 3
2 2 3
2 1 3
3 1 1
kth.out: 3
解釋: 先消除2,再消除1,再消除3,則全部消完。
30%數據:1<=n,m<=560%數據:1<=n,m<=7
100%數據: 1<=n,m<=8
100%數據:1<=顏?色<=n*m,保證初始每個格?子都>0,且最多有5種不同的顏?色。
IDA算法 待補~
T3 李世乭的單詞表
李世乭很喜歡背單詞,且對?自?己的記憶?力很有信?心,某天,他背了p開頭的?一些單詞
:
prada,pre,prepare,preview… 並放出豪?言:這些單詞我記得滾?瓜爛熟,甚?至可以倒背如流。 這可讓來?自美國的Alpha-Go不滿了,Alpha-Go說:我提問你?一系列問題,每個問 題問你:從你背的第L個單詞到第R個單詞中,有多少個以前綴X開頭的單詞,你能做到 麽?例如,L=2,R=4,X=“pre”,答案是3。 李世乭很快被問倒了,他表?示,世界上除了來?自中國的Anima-Out,沒?人能搞的 定,?身為Anima-Out的發明者你能夠幫他解決這個問題麽?輸入格式:
第一?行兩個正整數n,q,表?示李世乭背了n個單詞,Alpha-Go做了q次提問。 之後n?行,每?行?一個單詞。 之後q?行,每?行L,R,X,表?示詢問的區間以及前綴X。
註意:單詞並不是?一定按照字典序。
輸出格式:
q?行,每?行?一個整數,表?示對應問題的答案。
輸?入/輸出樣例:
dict.in:
4 2
prada
prepare
pre
preview
1 3 pre
1 4 pr
kth.out: 2 4
30%數據:n<=1000,q<=1000 100%數據:n<=100000,q<=100000 100%數據:每個單詞長度<=20且都是?小寫字母。
字典樹+前綴和,ORZ
#include <cstdio> #include <algorithm> #include <vector> #include <cstring> #include <string> #include <iostream> #include <string> using namespace std; int n,q; struct ve{ int flag,id; string word; }; struct node{ int num; int son[27]; }trie[100000*20]; vector<ve>now[100005]; string word[100005]; int ask[100005],tot,x,y; void Start(string word){ int now = 0; for(int i = 0;i<word.size();i++){ int j = word[i] - ‘a‘; if(trie[now].son[j]==0){ tot++; trie[now].son[j]=tot; } now = trie[now].son[j]; trie[now].num++; } } int find(string word){ int now = 0; for(int i=0;i<word.length();i++){ int j = word[i] - ‘a‘; if(trie[now].son[j]==0) return 0; now = trie[now].son[j]; } return trie[now].num; } int main(){ freopen("dict.in","r",stdin); freopen("dict.out","w",stdout); cin>>n>>q; for(int i=1;i<=n;i++){ cin>>word[i]; } for(int i=1;i<=n;i++) now[i].clear(); memset(ask,0,sizeof(ask)); memset(trie,0,sizeof(trie)); string fuck; ve sb; for(int i=1;i<=q;i++){ cin>>x>>y>>fuck; sb.flag=-1; sb.id=i; sb.word=fuck; now[x-1].push_back(sb); sb.flag=1; now[y].push_back(sb); } for(int i=1;i<=n;i++){ Start(word[i]); for(int j=0;j<now[i].size();j++){ ask[now[i][j].id]+=now[i][j].flag*find(now[i][j].word); } } for(int i=1;i<=q;i++){ cout<<ask[i]<<endl; } return 0; }
[OI模擬賽]2017.8.24 Day5