11.12 模拟题

来源:互联网 发布:苹果站电影源码 编辑:程序博客网 时间:2024/06/06 07:10

加密

【问题描述】

有一种不讲道理的加密方法是: 在字符串的任意位置随机插入字符。 相应的,不讲道理的解密方法就是从字符串中恰好删去随机插入的那些字符。给定原文s和加密后的字符串t,求t有多少子串可以通过解密得到原文s。

【输入格式】

输入第一行包含一个字符串t,第二行包含一个字符串s。

【输出格式】

输出一行,包含一个整数,代表可以通过解密得到原文的s的子串的数量。

【样例输入】

abcabcabccba

【样例输出】

9

【样例解释】

用[l,r]表示子串开头结尾的下标(从 0 开始编号) ,这 9 种方案是:[0,6],[0,7],[0,8],[1,6],[1,7],[1,8],[2,6],[2,7],[2,8]

【数据规模和约定】

30%的数据,|t|<=1000。对于100%的数据,1<=|t|<=300000,1<=s<=200。

思路;

就是找有多少子串中含有原文,子串中的原文(可以不连续)从0扫到lent(密文长度) 找能够含有原文的合法的子串找到一个子串后 对ans的贡献是(lent-end)*(i-wt) //具体含义见代码注意更新左边界 //防止计算重复的子串左边界应为上一个子串的起始位置

代码:

#include<cstdio>#include<cstring>#include<iostream>#define MAXN 300010#define INF 1000000000#define ll long longusing namespace std;char s[210],t[MAXN];int tot,len1,len2;ll ans;inline int find(int x) {    tot=0;    for(int i=x;i<len1;i++) {        if(t[i]==s[tot])           tot++;        if(tot==len2) return i;    }    return INF;}int main() {    freopen("encrypt.in","r",stdin);    freopen("encrypt.out","w",stdout);    cin>>t>>s;    len1=strlen(t);    len2=strlen(s);    int end,wt=-1;    for(int i=0;i<len1;i++) {        if(t[i]==s[0]) {            end=find(i);            if(end==INF) break;            ans+=(ll)(i-wt)*(len1-end);            wt=i;//更新边界        }    }    cout<<ans<<endl;    fclose(stdin);    fclose(stdout);    return 0;}

冒泡排序图

【问题描述】

有一段使用冒泡排序产生一张图的伪代码如下:function bubbleSortGraph(n, a[]):   graph = emptyGraph()   repeat     swapped = false     for i = 1 to n - 1:     if a[i] > a[i + 1]:     graph.addEdge(a[i], a[i + 1])     swap(a[i], a[i + 1])     swapped = true   until not swappedreturn graph函数的输入为长度为n的排列a[],输出为一张n个节点的无向图。函数中,emptyGraph()创造了一张空的无向图,addEdge(x, y)向图中添加了一条 x和 y 之间的无向边,最后返回的 graph 即产生的无向图。图的点独立集为图中节点集合的一个子集。如果集合S是图G的点独立集,那么S中任意两个节点在图G中都没有边直接相连。给定1~n的一个排列, 请求出按照伪代码生成的无向图的最大点独立集的大小,以及一定会存在于最大点独立集中的节点。

【输入格式】

输入第一行包含一个整数n。接下来一行包含n个空格分隔的整数,代表序列a[]。

【输出格式】

输出两行。 第一行包含一个整数, 代表生成的无向图的最大点独立集的大小。第二行输出最大点独立集中一定会包含的节点在输入序列中对应的下标, 按照从小到大的顺序输出,以空格分隔。

【样例输入】

33 1 2

【样例输出】

22 3

【数据规模和约定】

对于30%的数据,n<=16;对于60%的数据,n<=1000。对于100%的数据,1<=n<=100000。

【提示】

一定存在于最大点独立集中的节点数未必等于最大点独立集的大小。

思路:

此题纯属烧脑.....考试时模拟了半天 竟然是个LIS(最长上升子序列的变式) 晕~~~~第一问 :    一个点一定会与后面的一个小于当前数的数有一条边    例如 样例 3 1 2    3一定与1有连边,也一定与2有连边 而1不会与2有边    这样就构成了一个下降子序列 反过来不连边的点    就构成了上升子序列 最大独立子集就是求最长上升子序列的最大长度第二问:    一个序列中可能有多个上升子序列,所有上升子序列的公共点一定属于    最大独立子集,当然其他点也可能在,仅是可能,并不绝对    题目要求的的是一定存在的点

代码:

#include<cstdio>#include<iostream>#include<algorithm>#define MAXN 100010using namespace std;int a[MAXN],n;int tot,f[MAXN],c[MAXN];int sum[MAXN],maxx[MAXN];bool p[MAXN];inline void read(int&x) {    int f=1;x=0;char c=getchar();    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}    while(c>='0'&&c<='9') x=10*x+c-48,c=getchar();    x=x*f;}int main() {    read(n);    for(int i=1;i<=n;i++) read(a[i]);    for(int i=1;i<=n;i++) {        if(c[tot]<a[i]) {            c[++tot]=a[i];            f[i]=tot;        }        else {            int pos=upper_bound(c+1,c+1+tot,a[i])-c;            c[pos]=a[i];f[i]=pos;        }    }    printf("%d\n",tot);    for(int i=n;i>=1;i--) {        if(f[i]==tot||maxx[f[i]+1]>a[i]) {            p[i]=true;sum[f[i]]++;            maxx[f[i]]=max(maxx[f[i]],a[i]);        }    }    for(int i=1;i<=n;i++)      if(p[i]&&sum[f[i]]==1)        printf("%d ",i);    printf("\n");    return 0;}

重建

【问题描述】

给定一个n个点m条边的有向图。你可以选择一个节点x,然后重建所有能从x到达,而且能到达x的所有节点(包括x自身) 。此外,你还可以先将一条边改成双向边,然后再进行上面的选择。请你求出最多可以重建的节点数, 并求出通过选择哪些边改成双向边才能使重建的节点达到最多。

【输入格式】

输入的第一行包含两个整数n和m。接下来m行,每行包含两个整数u和v,描述一条有向边。保证图中任意两点在任意方向上最多只有一条边直接相连。

【输出格式】

输出三行。第一行输出一个整数,最多可以重建的节点数。第二一个整数k,代表有k条边能使重建节点数达到最多。第三行输出k个整数,代表可以选择的边的编号。边按照输入顺序从 1 开始编号。请按照从小到大的顺序输出,并以空格分隔。

【样例输入 1】

5 41 22 31 34 1

【样例输出 1】

313

【样例输入 2】

3 41 22 11 33 1

【样例输出 2】

341 2 3 4

【数据规模和约定】

对于30的数据,n,m<=10。        对于60%的数据,n<=1500,m<=100000。对于100%的数据,1<=n<=2000,m<=n*n。蒟蒻还在努力读题.........有神犇想到做法,就指点一下代码后面补上
0 0
原创粉丝点击