[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,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;
}
时间: 2024-10-07 14:13:09

[OI模拟赛]2017.8.24 Day5的相关文章

[铁一中OI模拟赛]2017.8.19 Day1

T1 小Z的情书 题目链接 思考: 题目主要难度在于旋转后的位置如何,在手写了样例之后不难发现规律. #include <cstdio> #include <cstring> #define up(a,b,c) for(register int c=a;c<=b;++c) #define down(a,b,c) for(register int c=a;c>=b;--c) const int Maxn=1005; int n; bool Map[Maxn][Maxn],

[铁一中OI模拟赛]2017.8.20 Day2

T1 LGTB 玩扫雷 题目链接 思考: 纯模拟题,没啥说的. #include <cstdio> #include <cstring> #define up(a,b,c) for(register int c=a;c<=b;++c) int n,m,map[1005][1005]; char s[233]; int fx[]={0,0,-1,-1,-1,0,1,1,1},fy[]={0,-1,-1,0,1,1,1,0,-1}; int main(){ //freopen(&

NOIP模拟赛(2017.9.15) -餐厅(restaurant)

餐厅(restaurant) [问题描述] 小R最近在玩一款模拟餐厅打工的游戏,其中有一个叠盘子的小游戏小R很喜欢.这个小游戏是这样的:有一个放盘子的机器会在一条直线上运动,机器里装着n个盘子,其中第i个盘子半径为ri,并且如果要放下该盘子,盘子的中心必须放在直线上xi的位置上,小R可以决定放下哪些盘子和放下这些盘子的顺序,盘子可以放在空位上,或者叠在一个上面没有其他盘子的盘子上,但要求被叠的盘子必须包含要叠上去的盘子.小R想要让叠出的盘子尽量高,请你计算出最高的一叠最多能叠几个盘子. [输入格

NOIP模拟赛(2017.9.15) -游戏(game)

游戏(game) [问题描述] 小R和小H在玩某个双人联机小游戏,一开始两人所操控的角色各有1点力量值,而在游戏中,每通过一关都会掉落一些力量强化道具.奇怪的是,明明是双人小游戏,每关却都会掉落3个相同的力量强化道具,于是两人决定每关每人先拿一个,剩下一个猜拳决定给谁.一个力量强化道具能使一个角色的力量值变为原来的若干整数倍,同一关卡掉落的道具倍率都相同,而不同的关卡可能不同.小R从攻略上找到了一些会产生特殊效果的力量值组合,他想知道哪些组合是按他们的道具分配方式有可能在通过某关时达成的. [输

[计蒜客NOIP模拟赛]2017.7.28Day1回顾反思总结

D1T1 打地鼠 题目链接 反思- 比赛得分-0 思考: 比赛时,以为T1是一道常规模拟题目,没怎么看数据范围.直接手动模拟,模拟完之后太自信也没有造数据Hack自己的程序.直接导致爆0.同时发现自己对二维前缀和的学习也只是在皮毛之上,没有深入思考与理解. 解题思路- 将图像旋转45°之后用二维前缀和维护,每次O(1)查询,时间复杂度O(N*N). 但是目前觉得这个图像旋转45°难以理解,打算手动模拟加深理解. 标程 #include<bits/stdc++.h> using namespac

【前行】◇第3站◇ 国庆训练营&#183;OI制模拟赛

[第3站] 国庆训练营·OI制模拟赛Ⅰ 怀着冲刺提高组400的愿望来到这个very small but very interesting 的训练营QwQ 在北大dalao的带领下开始了第一场OI模拟赛[炸心态ヽ(*.>Д<)o゜] ? 简单总结 感觉非常爆炸…… 第一题还好,一眼看出结论题,所以开始打表……没想到只打出来了一种情况(为什么全是特殊情况),然后就凉了. 第二题就开始崩溃了.首先画图思考了大概20分钟……然后发现想不出正解,就开始想要骗分.看了看数据阶梯,发现自己好像只能做前1/3

2017.11.25【NOIP提高组】模拟赛A组

2017.11.25[NOIP提高组]模拟赛A组 T1 3467. [NOIP2013模拟联考7]最长上升子序列(lis) T2 3468. [NOIP2013模拟联考7]OSU!(osu) T3 3472. [NOIP2013模拟联考8]匹配(match) T1 有转移方程f[i]=max{f[j]}+1,a[j]<a[i] 可以用线段树+离散化维护这个方程,因为涉及以往状态可以用主席树维护 打太丑爆空间了 Code 1 #include<cstdio> 2 #include<c

2017.6.11 校内模拟赛

题面及数据及std(有本人的也有原来的) :2017.6.11 校内模拟赛 T1 自己在纸上模拟一下后就会发现 可以用栈来搞一搞事情 受了上次zsq 讲的双栈排序的启发.. 具体就是将原盘子大小copy一下排个序 用两个指针维护两个数组(原数据 和 排序后的数据), 即分为1数据和2数组 将小于1指针指向的数据的2数组中的数据全部压入栈中 后进行消除, 将栈栈顶元素与当前1数组中的1指针指向的元素进行比较 相同则消除 后重复过程 直至指针超过N 后判断一下是否两个指针都超过了N... #incl

2017.12.02【NOIP提高组】模拟赛A组

2017.12.02[NOIP提高组]模拟赛A组 T1 3555[GDKOI2014模拟]树的直径 T2 3542[清华集训2014]冒泡排序 T3 3486[NOIP2013模拟联考10]道路改建(rebuild) T1 树直径的一个性质,两棵树合并,形成新的树的直径的两个端点为原树中的四个端点之二. 可以用反证法证明.用此性质本题就变成了lca裸题了 Code #include<cstdio> #include<cstring> #include<cmath> #i