题目名称 加密 冒泡排序图 重建
可执行文件名 encrypt bubble rebuild
输入文件名 encrypt.in bubble.in rebuild.in
输出文件名 encrypt.in bubble.out rebuild.in
每个测试点时限 1 秒 1 秒 1 秒
内存限制 512MB 512MB 512MB
测试点数目 10 20 10
每个测试点分值 10 5 10
是否有部分分 否 否 否
题目类型 传统型 传统型 传统型
测试题 #3 加密
加密
【问题描述】
有一种不讲道理的加密方法是: 在字符串的任意位置随机插入字符。 相应的,
不讲道理的解密方法就是从字符串中恰好删去随机插入的那些字符。
给定原文?和加密后的字符串?,求?有多少子串可以通过解密得到原文?。
【输入格式】
输入第一行包含一个字符串?,第二行包含一个字符串?。
【输出格式】
输出一行,包含一个整数,代表可以通过解密得到原文的?的子串的数量。
【样例输入】
abcabcabc
cba
【样例输出】
9
【样例解释】
用[?,?]表示子串开头结尾的下标(从 0 开始编号) ,这 9 种方案是:
[0,6],[0,7],[0,8],[1,6],[1,7],[1,8],[2,6],[2,7],[2,8]
【数据规模和约定】
30%的数据,|?| 1000。
对于100%的数据,1 ≤ |?| ≤ 300,000,1 ≤ ? ≤ 200。
/* 这题没想出来不应该啊 ..... 考试的时候考虑这样做 找每个最小的覆盖区间 但是有重复 似乎就搞到了容斥原理上 其实每找到一个区间 然后回头找 找到最近的合法的 假设 大区间是 [s,t] 回头找的是 [ss,t] 那么 我们累计贡献 (s-last)*(n-s+1) 下一次从ss开始找 last是上次一的ss在哪 这样就很好的解决了这个区间重复的问题 因为每次的起点限制在ss之后 而之前统计的区间起点都一定在ss之前 这样就好了 */ #include<cstdio> #include<cstring> #include<iostream> #define maxn 300010 using namespace std; int n,m; long long ans; char a[maxn],b[maxn]; int main() { freopen("encrypt.in","r",stdin); freopen("encrypt.out","w",stdout); scanf("%s%s",a+1,b+1); n=strlen(a+1);m=strlen(b+1); int s=0,t=0,st=0;while(s<=n){ if(a[++s]==b[t+1])t++; if(t==m){ for(int i=s;i>=1;i--){ if(a[i]==b[t])t--; if(t==0){t=i;break;} } ans+=(t-st)*(n-s+1);s=st=t;t=0; } } cout<<ans<<endl; fclose(stdin);fclose(stdout); return 0; }
测试题 #3 冒泡排序图
冒泡排序图
【问题描述】
有一段使用冒泡排序产生一张图的伪代码如下:
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 swapped
return graph
函数的输入为长度为?的排列?[],输出为一张?个节点的无向图。函数中,
emptyGraph()创造了一张空的无向图,addEdge(x, y)向图中添加了一条 x
和 y 之间的无向边,最后返回的 graph 即产生的无向图。
图的点独立集为图中节点集合的一个子集。如果集合?是图?的点独立集,
那么?中任意两个节点在图?中都没有边直接相连。
给定1~?的一个排列, 请求出按照伪代码生成的无向图的最大点独立集的大
小,以及一定会存在于最大点独立集中的节点。
【输入格式】
输入第一行包含一个整数?。接下来一行包含?个空格分隔的整数,代表序
列?[]。
【输出格式】
输出两行。 第一行包含一个整数, 代表生成的无向图的最大点独立集的大小。
第二行输出最大点独立集中一定会包含的节点在输入序列中对应的下标, 按照从
小到大的顺序输出,以空格分隔。
【样例输入】
3
3 1 2
【样例输出】
2
2 3
测试题 #3 冒泡排序
【数据规模和约定】
36。
60%的数据,? ≤ 1000。
对于100%的数据,1 ≤ ? ≤ 100,000。
【提示】
一定存在于最大点独立集中的节点数未必等于最大点独立集的大小。
测试题 #3 重建
傻逼暴力55
#include<iostream> #include<cstdio> #define maxn 100010 using namespace std; int n,a[maxn],f[maxn],g[maxn],ans; int init(){ int x=0,f=1;char s=getchar(); while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();} while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();} return x*f; } void Dfs(int x,int y){ for(int i=x-1;i>=1;i--) if(a[i]<a[x]&&f[i]+1==y){ g[i]=1;Dfs(i,f[i]); } } int main() { freopen("bubble.in","r",stdin); freopen("bubble.out","w",stdout); n=init(); for(int i=1;i<=n;i++) a[i]=init(),f[i]=1; for(int i=1;i<=n;i++) for(int j=1;j<i;j++) if(a[i]>a[j])f[i]=max(f[i],f[j]+1); for(int i=1;i<=n;i++) ans=max(ans,f[i]); for(int i=n;i>=1;i--) if(f[i]==ans){ g[i]=1;Dfs(i,ans); } printf("%d\n",ans); for(int i=1;i<=n;i++){ int falg=0;if(!g[i])continue; for(int j=i+1;j<=n;j++) if(f[i]==f[j]&&g[j]){ g[j]=0;falg=1; } if(!falg)printf("%d ",i); } fclose(stdin);fclose(stdout); return 0; }
改
改改
/* 自己改的跑了5s多 基本一个点就是同桌的total 这特么就很尴尬了 然后打开了std ..... 果然是把dfs找路径的过程改了 正着最长上升 到这最长 然而没有自己想的那么麻烦 a[i]=-a[i](就像懒得重载优先队列一样的*-1) 想到这句就好多了 多了 剩下的一毛一样 */ #include<iostream> #include<cstdio> #include<algorithm> #define maxn 100010 using namespace std; int n,a[maxn],c[maxn],num,f[maxn],g[maxn],r[maxn]; int init(){ int x=0,f=1;char s=getchar(); while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();} while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();} return x*f; } int main() { //freopen("bubble.in","r",stdin); //freopen("bubble.out","w",stdout); n=init(); for(int i=1;i<=n;i++)a[i]=init(); for(int i=1;i<=n;i++){ int x=a[i];if(x>c[num]){ c[++num]=x;f[i]=num;continue; } int pos=lower_bound(c+1,c+1+num,x)-c; c[pos]=x;f[i]=pos; } printf("%d\n",num);num=0;c[0]=-maxn; for(int i=n;i>=1;i--){ int x=-a[i];if(x>c[num]){ c[++num]=x;g[i]=num;continue; } int pos=lower_bound(c+1,c+1+num,x)-c; c[pos]=x;g[i]=pos; } for(int i=1;i<=n;i++) if(f[i]+g[i]==num+1)r[f[i]]++; for(int i=1;i<=n;i++){ if(f[i]+g[i]==num+1&&r[f[i]]==1) printf("%d ",i); } fclose(stdin);fclose(stdout); return 0; }
重建
【问题描述】
给定一个?个点?条边的有向图。你可以选择一个节点?,然后重建所有能
从?到达,而且能到达?的所有节点(包括?自身) 。此外,你还可以先将一条边
改成双向边,然后再进行上面的选择。
请你求出最多可以重建的节点数, 并求出通过选择哪些边改成双向边才能使
重建的节点达到最多。
【输入格式】
输入的第一行包含两个整数?和?。
接下来?行,每行包含两个整数?和?,描述一条有向边。
保证图中任意两点在任意方向上最多只有一条边直接相连。
【输出格式】
输出三行。第一行输出一个整数,最多可以重建的节点数。
第二一个整数?,代表有?条边能使重建节点数达到最多。
第三行输出?个整数,代表可以选择的边的编号。边按照输入顺序从 1 开始
编号。请按照从小到大的顺序输出,并以空格分隔。
【样例输入 1】
5 4
1 2
2 3
1 3
4 1
【样例输出 1】
3
1
3
【样例输入 2】
3 4
1 2
2 1
1 3
3 1
测试题 #3 重建
第 6 页 共 6 页
【样例输出 2】
3
4
1 2 3 4
【数据规模和约定】
3?,? ≤ 10。
60%的数据,? ≤ 1500,? ≤ 100,000。
对于100%的数据,1 ≤ ? ≤ 2000,? ≤ ? × ?。
30
/* 自己写的缩点然后求两点之间的最长路 wa了几个点 好奇的打开了数据 然而看不出啥 造了一坨小数据和暴力排 终于 发现了错误 不是求两点之间的最长路 有可能有两条路 或者更多 就比如 1->2->3 1->4->3 1->3 如果跑1->3的最长路 就弄丢了另一条 这特么就很尴尬了 数据还给了30分23333 经过一个小时的对拍+画图 终于找到了错误 然而不会改了.....不会改了 打开了std 很机智的bitset 然而不会用 于是乎弃疗了 答题的思路就是 维护每个点能到那些点 这里用位运算优化 然后剩下的思路就差不多了 */ #include<cstdio> #include<queue> #include<iostream> #define inf 1e8 #define maxn 2010 using namespace std; int n,m,num,head[maxn],mx[maxn][maxn],bl[maxn],cnt,ans[maxn*maxn],vis[maxn][maxn]; int N,M,Head[maxn],v[maxn],dfn[maxn],low[maxn],f[maxn],s[maxn],top,topt; queue<int>q; struct node{ int v,pre; }e[maxn*maxn],p[maxn*maxn]; struct edge{ int u,v; }E[maxn*maxn]; int init(){ int x=0,f=1;char s=getchar(); while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();} while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();} return x*f; } void Add(int from,int to){ num++;e[num].v=to; e[num].pre=head[from]; head[from]=num; } void Ad(int from,int to){ printf("%d %d\n",from,to); if(vis[from][to])return; vis[from][to]=1; M++;p[M].v=to; p[M].pre=Head[from]; Head[from]=M; } void Tarjan(int x){ dfn[x]=low[x]=++topt; f[x]=1;s[++top]=x; for(int i=head[x];i;i=e[i].pre){ int v=e[i].v; if(dfn[v]==0){ Tarjan(v);low[x]=min(low[x],low[v]); } else if(f[v])low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]){ N++;while(x!=s[top]){ v[N]++;bl[s[top]]=N;f[s[top]]=0;--top; } v[N]++;bl[s[top]]=N;f[s[top]]=0;--top; } } /*void Dfs(int s,int now,int from){ mx[s][now]=max(mx[s][now],mx[s][from]+v[now]); for(int i=Head[now];i;i=p[i].pre){ int v=p[i].v;Dfs(s,v,now); } }*/ void SPFA(int s){ for(int i=1;i<=n;i++)f[i]=0; f[s]=1;mx[s][s]=v[s];q.push(s); while(!q.empty()){ int k=q.front();f[k]=0;q.pop(); for(int i=Head[k];i;i=p[i].pre){ int to=p[i].v; if(mx[s][to]<mx[s][k]+v[to]){ mx[s][to]=mx[s][k]+v[to]; if(f[to]==0){ f[to]=1;q.push(to); } } } } } int main() { freopen("rebuild.in","r",stdin); freopen("rebuild.out","w",stdout); n=init();m=init();int u,v; for(int i=1;i<=m;i++){ u=init();v=init();Add(u,v); E[i].u=u;E[i].v=v; } for(int i=1;i<=n;i++) if(dfn[i]==0)Tarjan(i); printf("\n"); for(int u=1;u<=n;u++) for(int i=head[u];i;i=e[i].pre){ int v=e[i].v;if(bl[u]==bl[v])continue; Ad(bl[u],bl[v]); }printf("\n"); for(int i=1;i<=N;i++)SPFA(i); //Dfs(i,i,0); int mxx=0; for(int i=1;i<=m;i++){ u=bl[E[i].u];v=bl[E[i].v]; if(mx[u][v]>mxx){ mxx=mx[u][v]; cnt=0;ans[++cnt]=i; } else if(mx[u][v]==mxx) ans[++cnt]=i; } printf("%d\n%d\n",mxx,cnt); for(int i=1;i<=cnt;i++) printf("%d ",ans[i]); return 0; }