假发通过了不懈的努力,得到了将军家门锁的密码(一串小写英文字母)。但是假发被十四和猩猩他们盯上了,所以假发需要把密码传递出去。因为假发不想十四他们发现几松门前贴的小纸条就是将军家的密码,所以他加密了密码(新八:听起来有点诡异)。加密方法如下:随机地,在密码中任意位置插入随机长度的小写字符串。
不过,假发相信银桑和他那么多年小学同学,一定能猜中密码是什么的(新八:银桑什么时候成攮夷志士了!!!)。可是,写完了小纸条之后,假发觉得有点长,就想截去头和尾各一段(可以为空),让剩下的中间那一段依然包含真~密码。想着想着,假发就想知道有多少种可行方案。结果在沉迷于稿纸之际,假发被投进了狱门岛(新八:……)。于是,就由你计算了。
输入
两行非空字符串,纯小写英文字母,第一行是加密后的密码,第二行是原密码。
第一行长度不超过300000,第二行不超过200。
输出
一行,有多少种方案。注意:不剪也是一种方案。
样例输入
abcabcabc cba
样例输出
9
提示
【样例解释】
用(L,R)表示一种方案,其中L和R分别表示截去头和尾的长度。这9钟方案分别是(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)。
【数据说明】
30%的数据满足第一行长度不超过1000。
一拿到此题懵逼,开始以为是裸裸的KMP,后来发现暴力就是可以水过。f[i][j]表示第i个节点之后最近的j字符的位置。这样我们每次枚举起点在原字符串种的位置,一次次往下跳即可。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define N 300005 using namespace std; char stra[N+10],strb[N+10]; int lena,lenb,last; int next[N+10][26],dictionary[26]; long long ans; int main() { scanf("%s %s",stra+1,strb+1); int lena=strlen(stra+1); int lenb=strlen(strb+1); for(int i=lena;i>=1;i--) { memcpy(next[i],dictionary,sizeof(next[i])); dictionary[stra[i]-‘a‘]=i; } for(int i=1;i<=lena;i++) if(stra[i]==strb[1]) { int p=i,t=1; bool flag=1; while(t<lenb) { p=next[p][strb[++t]-‘a‘]; if(p==0) { flag=0; break; } } if(!flag) continue; ans+=(lena-p+1)*(i-last); last=i; } cout<<ans<<endl; }
题 B: 独立集
时间限制: 1 Sec 内存限制: 128 MB
提交: 155 解决:
32
[提交][状态][讨论版]
题目描述
有一天,一个名叫顺旺基的程序员从石头里诞生了。又有一天,他学会了冒泡排序和独立集。在一个图里,独立集就是一个点集,满足任意两个点之间没有边。于是他就想把这两个东西结合在一起。众所周知,独立集是需要一个图的。那么顺旺基同学创造了一个算法,从冒泡排序中产生一个无向图。
这个算法不标准的伪代码如下:
procedure
bubblesortgraph(n, a[]) :
/*输入:点数n,1到n的全排列a。
输出:一个点数为n的无向图G。*/
创建一个有n个点,0条边的无向图G。
repeat
swapped = false
for i 从
1
到 n-1 :
if a[i] > a[i + 1]
:
在G中连接点a[i]和点a[i + 1]
交换a[i]和a[i + 1]
swapped = true
until not
swapped
输出图G。
//结束。
那么我们要算出这个无向图G最大独立集的大小。但是事情不止于此。顺旺基同学有时候心情会不爽,这个时候他就会要求你再回答多一个问题:最大独立集可能不是唯一的,但有些点是一定要选的,问哪些点一定会在最大独立集里。今天恰好他不爽,被他问到的同学就求助于你了。
输入
两行。第一行为N,第二行为1到N的一个全排列。
输出
两行。第一行输出最大独立集的大小,第二行从小到大输出一定在最大独立集的点的编号(输入时的序号)。
样例输入
3 3 1 2
样例输出
2 2 3
提示
【数据范围】
30%的数据满足 N<=16
60%的数据满足 N<=1,000
100%的数据满足 N<=100,000
哈哈刚写过求LIS的nlogn方法,就考到了~ ~开心。
这道题就是求一个LIS,问哪些点一定在LIS的序列里。我们把每个点向左和向右的LIS算出来,如果相加=最长上升子序列数+1则代表这个点可以是最长上升子序列中的一点。如果这个二元组没有重复出现过,就代表它不能被替换。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<vector> #include<map> using namespace std; typedef long long ll; typedef long double ld; typedef pair<int,int> pr; const double pi=acos(-1); #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define Rep(i,u) for(int i=head[u];i;i=Next[i]) #define clr(a) memset(a,0,sizeof(a)) #define pb push_back #define mp make_pair #define fi first #define sc second #define pq priority_queue #define pqb priority_queue <int, vector<int>, less<int> > #define pqs priority_queue <int, vector<int>, greater<int> > #define vec vector ld eps=1e-9; ll pp=1000000007; ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; ll read(){ ll ans=0; char last=‘ ‘,ch=getchar(); while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar(); while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar(); if(last==‘-‘)ans=-ans; return ans; } #define N 100005 map<pr,int> Map; int B[N],a[N],Left[N],n,b[N],Right[N],Len; void init() { n=read(); rep(i,1,n) a[i]=read(); } void LIS() { B[1]=a[1];int len=1;Left[1]=1; for(int i=2;i<=n;i++) { if(a[i]>B[len]) B[++len]=a[i]; int pos=lower_bound(B+1,B+1+len,a[i])-B; B[pos]=a[i]; Left[i]=pos; } Len=len; } void RE_LIS() { memset(B,0,sizeof(B)); for(int i=1;i<=n;i++) b[i]=a[i]; for(int i=1;i<=n;i++) a[i]=-b[n-i+1]; B[1]=a[1];int len=1;Right[n]=1; for(int i=2;i<=n;i++) { if(a[i]>B[len]) B[++len]=a[i]; int pos=lower_bound(B+1,B+1+len,a[i])-B; B[pos]=a[i]; Right[n-i+1]=pos; } } void Debug() { for(int i=1;i<=n;i++) cout<<Left[i]<<‘ ‘<<Right[i]<<endl; } int main() { init(); LIS(); RE_LIS(); //Debug(); cout<<Len<<endl; for(int i=1;i<=n;i++) if(Left[i]+Right[i]-1==Len) { Map[mp(Left[i],Right[i])]++; } for(int i=1;i<=n;i++) if(Map[mp(Left[i],Right[i])]==1) printf("%d ",i); }