题目:
【 Beads】 new oj 1585:
题目大意: 现在给你一个数字的序列,现在你可以把他分成每段k长度的若干段,最后一段不足k的舍弃,求最多能得到多少相同的序列?(1,2,3和3,2,1是一样的。)(n<=200005);
思路
可以枚举每个k,然后把所有的串进行一个hash,这样的话就可以直接把每一个k得出的所有的hash值放到一个数组里面去重一下就可以了。
Tips : (1<=k<=n)sigma(n/k)可以证明复杂度是nlong(n)。
这样就可以写程序了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#define seed 19990213
#define F(i,begin,end) for(int i=begin;i<=end;i++)
using namespace std;
const int imax=200005+229;
typedef unsigned long long US;
int n; int a[imax];
int K;
int ans[imax],num;
US f[imax],d[imax],ff[imax],lishi[imax];
int get(int x)
{
int l=1; int r=x;
int s=0;
while(r<=n)
{ //正反都hash一遍。
US hash1=(f[r]-f[l-1]*d[x]);
US hash2=(ff[l]-ff[r+1]*d[x]);
lishi[++s]=min(hash1,hash2);
l+=x; r+=x;
}
sort(lishi+1,lishi+s+1);
int gay=unique(lishi+1,lishi+s+1)-(lishi+1);
return gay;
}
void iwork()
{
d[0]=1;
for(int i=1;i<=n;i++)
{
f[i]=f[i-1]*seed+a[i];
d[i]=d[i-1]*seed;
}
for(int i=n;i>=1;i--) ff[i]=ff[i+1]*seed+a[i];
for(int i=1;i<=n;i++)
{
int nowans=get(i);
// printf("%d %d\n",i,nowans);
if(nowans>K) ans[num=1]=i,K=nowans;
else if(nowans==K) ans[++num]=i;
}
printf("%d %d\n",K,num);
for(int i=1;i<num;i++) printf("%d ",ans[i]);
printf("%d",ans[num]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
iwork();
return 0;
}
【Intelligence】 new oj 1588:
题目大意:霸中智力测试机构的一项工作就是按照一定的规则删除一个序列的数字,得到一个确定的数列。
Lyx很渴望成为霸中智力测试机构的主管,但是他在这个工作上做的并不好,俗话说熟能生巧,
他打算做很多练习,所以他希望你写一个程序来快速判断他的答案是否正确。
原序列长度为m, 查询次数为n, 每次查询的长度小于m。
(1<=n,m<=1000000)
思路
对于一个查询的串,首先前面的数字肯定要越小越好,这样后面才有更多的可能性。所以直接开m个不定数组来保存某个数字出现的所有时刻。这样每次都只要二分查找即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
const int imax=1000000+229;
int n,m,T;
int a[imax],now[imax];
vector<int> q[imax];
void iread()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
q[a[i]].push_back(i);
}
scanf("%d",&T);
}
int find(int k,int x)
{
int l=0,r=q[x].size()-1;
int ans=imax;
while(l<=r)
{
int mid=(l+r)>>1;
if(q[x][mid]>k) ans=q[x][mid],r=mid-1;
else l=mid+1;
}
return ans;
}
void iwork()
{
while(T--)
{
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d",&now[i]);
bool flag=0; int last=0;
for(int i=1;i<=m;i++)
{
int pos=find(last,now[i]);
if(pos>n) { flag=1; break;}
last=pos;
}
flag==0 ? puts("TAK") : puts("NIE");
}
}
int main()
{
iread();
iwork();
return 0;
}
【Pilots(pilots)】 new oj 1589:
题目大意:Tz又耍畸形了!!他要当飞行员,他拿到了一个飞行员测试难度序列,他设定了一个难度差的最大值,在序列中他想找到一个最长的子串,任意两个难度差不会超过他设定的最大值。
思路
显然只要保存两个个单调的队列,一个保存最大值一个保存最小值就可以。考场上想复杂了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#define F(i,begin,end) for(int i=begin;i<=end;i++)
using namespace std;
const int imax=3000000+229;
int n,k;
int a[imax];
int Max[imax],Min[imax];
int Maxp[imax],Minp[imax];
void iread()
{
scanf("%d%d",&k,&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
}
void iwork()
{
int Bhead=1,Btail=2; Max[1]=a[1]; Maxp[1]=1;
int Shead=1,Stail=2; Min[1]=a[1]; Minp[1]=1;
int l=1; int r=1;
while(Max[Bhead]-Min[Shead]<=k && r<n)
{
++r;
while(a[r]>Max[Btail-1] && Btail>Bhead) Btail--;
Max[Btail]=a[r]; Maxp[Btail]=r; Btail++;
while(a[r]<Min[Stail-1] && Stail>Shead) Stail--;
Min[Stail]=a[r]; Minp[Stail]=r; Stail++;
}
int len=0;
if(r==n)
{
if(Max[Bhead]-Min[Shead]<=k) printf("%d\n",n);
else printf("%d\n",n-1);
return;
}
len=max(r-l,len);
while(r<=n)
{
while(Max[Bhead]-Min[Shead]>k && l<r)
{
l++;
if(Maxp[Bhead]<l && Bhead<Btail-1) Bhead++;
if(Minp[Shead]<l && Shead<Stail-1) Shead++;
}
len=max(len,r-l);
while(Max[Bhead]-Min[Shead]<=k && r<n)
{
++r;
while(a[r]>Max[Btail-1] && Btail>Bhead) Btail--;
Max[Btail]=a[r]; Maxp[Btail]=r; Btail++;
while(a[r]<Min[Stail-1] && Stail>Shead) Stail--;
Min[Stail]=a[r]; Minp[Stail]=r; Stail++;
}
if(r==n)
{
if(Max[Bhead]-Min[Shead]<=k) len=max(len,n-l+1);
else len=max(len,r-l);
break;
}
else len=max(len,r-l);
}
printf("%d\n",len);
}
int main()
{
iread();
iwork();
return 0;
}