題目:
【 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;
}