8.7联考题解

前两题很水啊……没必要开三篇了就扔到一篇里去了。改水题异常艰难,代码量很小然而我又被什么奇怪的东西绊住了。

Passward

时间限制: 1 Sec  内存限制: 512 MB

题目描述

你来到了一个庙前,庙牌上有一个仅包含小写字母的字符串 s。

传说打开庙门的密码是这个字符串的一个子串 t,并且 t 既是 s 的前缀又是 s 的后缀并且还在 s 的中间位置出现过一次。

如果存在这样的串,请你输出这个串,如有多个满足条件的串,输出最长的那一个。

如果不存在这样的串,输出"Just a legend"(去掉引号)。

输入格式

仅一行,字符串 s。

输出格式

如题所述

样例输入

fixprefixsuffix

样例输出

fix

数据范围

对于 60%的数据, s 的长度<=100

对于 100%的数据, s 的长度<=100000

题解

       一拿到卷子……诶,这个题,出题人真当我们没做过cogs一星题吗……就是小暑假集训最后一天大家刷GT考试刷不动了集体去水的那道题嘛。然而由于本蒟蒻字符串的题组做得极慢,所以并没有去水这道题。反正是KMP,没做过现在做也是一样,不过KMP的板子记得不太清楚,还是先往后看。把第二题的暴力分拿到回来看这题,好像我跟wzz讨论过这题应该怎么水,然后用我的o(N)想法没跑过暴力验证……调一调01边界什么的把MP打出来,这题也用不着KMP了,手出几个特殊样例测测都没啥问题,题目好像也没说不能重叠什么的(adadadadada~),反正很多人都A了我也A了就是了。

中午回cogs去水鱼的感恩,迷之数据范围,开始因为题都没看果断WA,把WA改对了开始T。cogs下面附了一句题源:XXX或51nod1286,然后我欣然去了51nod,发现那道题居然是不允许重叠的。不可以重叠这个要怎么搞啊10^6,不会不会不会……自己挣扎了一个多小时开始问dalao,老白轻描淡写地回答:“hash水之”(不要啊我不想放弃机智的KMP);张司机说:“可以从中间往后枚举啊,不过这个数据范围总有点不祥预感”;ryf说:“等我过了这个题给你讲”。我回来改了改cogs的数组大小发现居然是因为memset超时,然而51nod那题实在没法,打表过第二个点(这居然是唯一一个能卡住毫无根据的依据三倍长度判断的点),去看别人代码。最后在自己的艰苦斗争和ryf大佬的提点下发现这题只有两种方法可以过:hash和扩展KMP。所以我一个不会扩展KMP又不想打hash的人这一下午是为了什么啊喂……自己去看了看扩展KMP的资料,原理还好,要用不还是个板子。处理完我唯一过掉的那题已经快吃晚饭了,我开始改剩下两题……

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int sj=100010;
char s[sj];
int len,nt[sj]={0};
bool cx[sj]={0};
void gn()
{
     nt[1]=nt[0]=0;
     for(int i=2,k=0;i<=len;i++)
     {
        while(k&&s[i-1]!=s[k]) k=nt[k];
        if(s[i-1]==s[k]) k++;
        nt[i]=k;
        if(i!=len) cx[nt[i]]=1;
     }
}
int main()
{
    //freopen("t1.txt","r",stdin);
    scanf("%s",s);
    len=strlen(s);
    gn();
    int jg=nt[len];
    while(jg&&!cx[jg])
      jg=nt[jg];
    if(jg==0) printf("Just a legend");
    else
      for(int i=len-jg;i<len;i++)
        cout<<s[i];
    //while(1);
    return 0;
}

password

时间限制: 1 Sec  内存限制: 512 MB

【背景描述】

一排 N 个数, 第 i 个数是 Ai , 你要找出 K 个不相邻的数, 使得他们的和最大。

请求出这个最大和。

【输入格式】

第一行两个整数 N 和 K。

接下来一行 N 个整数, 第 i 个整数表示 Ai 。

【输出格式】

一行一个整数表示最大和, 请注意答案可能会超过 int 范围

【样例输入】

3 2

4 5 3

【样例输出】

7

【数据范围】

对于 20% 的数据, N, K ≤ 20 。

对于 40% 的数据, N, K ≤ 1000 。

对于 60% 的数据, N, K ≤ 10000 。

对于 100% 的数据, N, K ≤ 100000 , 1 ≤ Ai ≤ 1000000000。

【题解】

      这个题目,一看它就很将就……刚开始照例想一遍网络流,建出来图了,Dinic我都打好了,忽然想到网络流怎么限制只选K个数呢……(据某神犇wxh说可以建一个假原点跑费用流,%%%)然后就开始弃疗了,正什么解想暴力。10^4的数据n^2是能过的,然后n^2的dp也很好想,f[i][j]表示到第i位选了j个数,肯定要从f[k][j-1]转移(k<=i-2),拿一个数组记录一下到i-2的最大值,转移很方便。为了优化再看每个i需要计算到多大的j,毕竟i个数里最多选i>>1个。10^4数组差不多能开,但是毕竟想试试运气还是滚动了一下然后把数组开到了10^5,然而事实证明跑不过就是跑不过。60分差不多就算把暴力分都拿到了吧,手出几个样例挑出来几个不是很明显的bug,想想还是有些后怕,果然我该去学对拍了。后来发现第三题一点分拿不到再回来想这道题,感觉正解必须把n甩掉,n*k的效率跑死也过不了,而枚举k又是必须的;尽管如此并没有想到应该怎么做。

正解是带反悔的贪心,用一些简单的数据结构来支持。用堆维护所有点,每次选中权值最大的点,把它和两侧的点合并为一个点,再把三个原来的点删去,新的点权值设为两侧点-中间被选点权值,方便过后反悔,处理一下前后边界让新的点代替原来的三个点即可。往常都是拿堆水dp,今天居然也有拿dp水堆的时候。晚上改这个题,就是不想用链表也不想用set,感觉两个堆也能做,只要把左右边界指向那个合并后的结构体都可以了。思路一直很清楚,就卡在那么两三个点上过不去,挣扎了一个晚上。有两个点是因为边界限制得太狠,就算已经到了边界也没有特殊处理,而贪心的正确性建立在每次有且只有一个点新被选中的基础上。然后改到晚上睡觉也没改过,宿舍在六楼昨晚蚊子却迷之多,三点多就被闹醒,从蚊帐里抓住了五只不知道什么玩意扔出去,迷迷糊糊一直在想这道题到底什么鬼,想着想着就到点了,被咬得浑身都疼。早上来了之后在结构体重载里加了个如果权值相等按下表排序,莫名其妙就过了。写博客的时候忽然开窍,大概是因为这样一来每个结构体一定会分出确定的顺序,在用垃圾堆删除结构体的时候就能满足在原队列中优先的在垃圾堆中也一定优先,就不会导致用垃圾堆删除结构体不准确了。这样一个小bug折腾了一晚上一早上,把本题的提交正确率拉到极低,过程中万分痛苦,想通了之后却觉得很有意思。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int sj=100010;
int n,k,tp;
struct W
{
    int l,r,size;
    long long w;
    bool operator > (const W &f) const
    {  return w<f.w||(w==f.w&&l<f.l);  }
    bool operator == (const W &f) const
    {  return w==f.w&&l==f.l&&r==f.r;  }
    void in(int x)
    {
        l=r=x;
        scanf("%lld",&w);
    }
}b[sj],temp;
priority_queue<W, vector<W> , greater<W> > a;
priority_queue<W, vector<W> , greater<W> > c;
long long ans;
int main()
{
    scanf("%d%d",&n,&k);
    memset(b,-0xf,sizeof(b));
    b[n+1].r=n+1;
    b[0].l=0;
    for(int i=1;i<=n;i++) b[i].in(i),a.push(b[i]);
    for(int i=1;i<=k;i++)
    {
        while(!c.empty()&&a.top()==c.top())
           a.pop(),c.pop();
        temp=a.top();
        a.pop();
        ans+=temp.w;
        temp.w=-temp.w;
        if(temp.l!=0)
        {
          temp.w+=b[temp.l-1].w;
          c.push(b[temp.l-1]);
          temp.l=b[temp.l-1].l;
        }
        if(temp.r!=n+1)
        {
          temp.w+=b[temp.r+1].w;
          c.push(b[temp.r+1]);
          temp.r=b[temp.r+1].r;
        }
        b[temp.r]=b[temp.l]=temp;
        a.push(temp);
    }
    printf("%lld",ans);
    return 0;
}

so

时间限制: 1 Sec  内存限制: 512 MB

【题目描述】

Hazel有n本书,编号1为n到 ,叠成一堆。当她每次抽出一本书的时候,上方的书会因重力而下落,这本被取出的书则会被放置在书堆顶。

每次有pi的概率抽取编号为i的书。她每次抽书所消耗的体力与这本书在这堆中是第几本成正比。具体地,抽取堆顶的书所耗费体力值为1 ,抽取第二本耗费体力值为2 ,以此类推。

现在 想知道,在很久很久以后(可以认为几乎是无穷的),她每次抽书所耗费的体力的期望值是多少。

最终的答案显然可以表示成a/b的形式,请输出a*(b^-1)模1e9+7的值。

【输入格式】

第一行一个整数n

接下来n行,每行两个整数ai,bi,代表抽取第i本书的概率是ai/bi

保证所有书的概率和等于1

【输出格式】

输出一行一个整数,代表期望值

【输入样例1】

2

227494 333333

105839 333333

【输出样例1】

432679642

【输入样例2】

10

159073 999999

1493 142857

3422 333333

4945 37037

2227 111111

196276 999999

190882 999999

142721 999999

34858 999999

101914 999999

【输出样例2】

871435606

【数据规模与约定】

对于30%的数据,1<=n<=10。

对于100%的数据,1<=n<=1000,0<=ai<=bi,bi!=0。

【题解】

刚看到这个题,推一推好像不用高斯消元,莫名挺开心,到后来我都不知道我在高兴些什么……有一种很错误的想法,叫做不用高斯消元就要递推,然后坚信一定要从第一本或者最后一本的期望推出其他书的期望,一直抓着期望=概率*权值不放,位置的期望*概率=耗费体力的期望,但是连样例都不知道应该怎么出。感觉要是有哪位dalao做出来了这题也就AK了吧,结果出人意料又情理之中地全场爆零,真想赞美一下出题人。我很弱+题很强=迷之得分率。

正解是一个简单却不好想的式子,每本书的位置取决于是否有书比它更晚被抽到,所以E[i]=sigma(p[j]/(p[i]+p[j])) , (1<=j<=n&&j!=i),ans=sigma(1+E[i])。虽然给出的和要求的都是分数,但是是在同一个模意义下,所以从一开始就逆元就好了。连续背了很多顿饭之后我终于会写扩展欧几里得了可喜可贺可喜可贺。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int sj=1005;
const ll mod=1000000007;
int n;
ll jg,p[sj],a1,a2,tp;
ll e_gcd(ll n,ll m,ll &sx,ll &sy)
{
     if(m==0)
     {
        sx=1;
        sy=0;
        return n;
     }
     ll ans=e_gcd(m,n%m,sx,sy);
     ll t=sx;
     sx=sy;
     sy=t-n/m*sy;
     return ans;
}
ll ny(ll a,ll b)
{
     ll sx,sy;
     ll gcd=e_gcd(a,b,sx,sy);
     sx*=1/gcd;
     b/=gcd;
     if(b<0) b=-b;
     ll ans=sx%b;
     if(ans<0) ans+=b;
     return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
       scanf("%lld%lld",&a1,&a2);
       a1%=mod;
       p[i]=a1*ny(a2,mod)%mod;
    }
    for(int i=1;i<=n;i++)
    {
       tp=0;
       for(int j=1;j<=n;j++)
         if(i!=j)
           tp=(tp+(p[j]*ny((p[i]+p[j])%mod,mod))%mod)%mod;
       jg=(jg+(p[i]*(1+tp)%mod))%mod;
    }
    printf("%lld",jg);
    return 0;
}

book

时间: 2024-11-04 10:21:20

8.7联考题解的相关文章

3.5~3.6联考题解

本来想加个密码的,后来一想全HE就咱们这几个人,外省的dalao愿看也没事儿,就公开算了,省得加密码各种麻烦. 先补这两天的题解吧--如果有空的话我可能会把上次联考的题解补上= =(中午没睡觉,现在困得很,根本没法写题-- 算算算number 感觉出题人出题的时候zz了吧,费了半天搞出来一个极其麻烦还跑得慢的做法是要闹哪样啊-- 算了,写一写$O(nk)$做法的推导过程吧,虽然其实非常好推-- 首先定义$S_i$表示到$1~i$位置的前缀和,并且规定$S_0=0$,那么 \begin{align

8.9联考题解

今天的题有质量多了,尤其是第一题不再毫无意义,果然考这样的试比较有收获. 时间限制:1sec  内存限制:128MB 题解       刚开始看的时候没有思路.不过这样的考试才叫正常嘛,前两天T1那是什么玩意= =.边读题边写前缀和.离散之类的词,但是前缀和并不能处理出题目中所要求的情况,3*10^5大概最多nlogn.举了几个例子,发现好像和后面大于它的数有关,想了想怎么求它后面大于它的数字个数,过了一会猛然发现我举的例子也太特殊了,全都是单调递增的,有点挫败,就去做后面的题了.T2做了很久还

8.8联考题解

今天的T1让我怀疑我是不是在做奥赛题--这考的是什么知识点啊这个,会不会用绝对值函数? Evensgn 的债务 时间限制: 1 Sec  内存限制: 128 MB 题目描述 Evensgn 有一群好朋友,他们经常互相借钱.假如说有三个好朋友A,B,C.A 欠 B 20 元,B 欠 C 20 元,总债务规模为 20+20=40 元.Evensgn 是个追求简约的人,他觉得这样的债务太繁杂了.他认为,上面的债务可以完全等价为 A 欠C20 元,B 既不欠别人,别人也不欠他.这样总债务规模就压缩到了 

8.13联考题解

最长上升子串 时间限制: 2 Sec  内存限制: 64 MB 样例输入 67 2 3 1 5 6 样例输出 5 题解       刚一读题觉得和昨天T3相似度极高,只不过是久违的子串.还是想动归思路,f[i][1/0]表示到第i位是/否已经改变过序列的值,然后大概就是个择优转移的思路:受到昨天那题局限用一个辅助数组记录了一下改变后的值,贪心策略把它设为a[i-1][0]+1,.开始上手打,代码倒是很短,怎么想怎么觉得不对劲,自己凭着感觉开始刻意造数据卡这个做法.试了几组数之后成功用123745

8.10联考题解

早上起来莫名困,天天晚上十点睡为什么会困我也不是很懂--然后就迷迷瞪瞪做题,一直都不大清醒.因为一点智障的知识漏洞T3完全挂,然后T2炸内存T1做了两个多小时没做出来~但是也只能说明自己弱,好在现在发现这些坑总比联赛之后发现好得多吧. Evensgn 剪树枝 出题人:Vincent 时间限制:1s 空间限制:128MB 题目描述 繁华中学有一棵苹果树.苹果树有 n 个节点(也就是苹果),n ? 1 条边(也就是树枝).调皮的 Evensgn 爬到苹果树上.他发现这棵苹果树上的苹果有两种:一种是黑

8.12联考题解

所谓今天的题格外水,dalao们纷纷AK--但是本蒟蒻并没有看出来有多水啊--虽然还是水过了一道题,然后剩下的题就照常地转不过来弯,分数和往常并没有多大变化= =. 灌水 时间限制:1s 空间限制:256MB 样例输入1: 3 1 样例输出1: 3 1 2 样例输入2: 4 1 样例输出2: 4 3 1 2 样例输入3: 8 17 样例输出3: 6 2 3 1 8 4 5 7 题解       这个题,第一眼看过去很interesting,第二眼看过去一脸茫然--头一遍读题的时候看到数据范围里那

8.11联考题解

样例输入: 3 6 0 -1 1 1 0 -1 -1 1 0 1 2 3 1 2 3 样例输出: 3 题解      不要看上面那个吓人的时间限制--实际上内网给了4Sec,高明的模拟能过:外网给的时间比这还多,直接暴力模拟就能A,这就是为什么我今天成绩莫名高了不少.刚开始就只想到了模拟,用链表可以稍微优化一点有限,然而时间效率近似于n*答案,要依靠答案的大小来决定时间效率,让我不由得想到某名为<天鹅会面>的惨痛事故.想了很久还是没想出来,直接把模拟当做骗分程序来写,连快读都没有写:自认为是今

2015.10.16赛码联考题解,非正确,求大神指导。

//只AC了20%.说的就是11个位置一字型排开0-10.扔硬币到这些位置,然后有个帽子可以每次移动最多一个位置,初始位置5. //思考:相当于遍历一个3叉树. #include <iostream>#include <vector>#include <cmath>using namespace std; struct coins{ int x; int T;};int main (){ int n,i,j,k; coins coins1[100000]={0}; in

10.29 FJ四校联考

//四校联考Rank 16 感觉很滋磁 (虽然考的时候抱怨厦门一中出的数学题很NOIP///) 圈地 [问题描述] n根长度不一定相同的木棍,至多可以对其中一根切一刀,然后用其中的任意根围一个三角形,求三角形的最大面积.设面积为S,输出16*S^2对998244353取模后的答案.特别地,无解输出-1. 注:退化的三角形(面积为零)不被认为是三角形,答案应该为-1. [输入文件] 输入文件为tri.in. 输入文件第一行包含两个正整数n和998244353. 第二行包含n个正整数,表示每根木棍的