1. 程式人生 > >[OI模擬賽]2017.8.24 Day5

[OI模擬賽]2017.8.24 Day5

ostream emp 模擬 fin book clas hellip 我不 nim

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,000

60%數據: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<=5

60%數據: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