首页 > 代码库 > USACO 5.1 Musical Themes(哈希+二分)

USACO 5.1 Musical Themes(哈希+二分)

Musical Themes
Brian Dean

A musical melody is represented as a sequence of N (1 <= N <= 5000) notes that are integers in the range 1..88, each representing a key on the piano. It is unfortunate but true that this representation of melodies ignores the notion of musical timing; but, this programming task is about notes and not timings.

Many composers structure their music around a repeating "theme", which, being a subsequence of an entire melody, is a sequence of integers in our representation. A subsequence of a melody is a theme if it:

  • is at least five notes long
  • appears (potentially transposed -- see below) again somewhere else in the piece of music
  • is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s)

Transposed means that a constant positive or negative value is added to every note value in the theme subsequence.

Given a melody, compute the length (number of notes) of the longest theme.

One second time limit for this problem‘s solutions!

PROGRAM NAME: theme

INPUT FORMAT

The first line of the input file contains the integer N. Each subsequent line (except potentially the last) contains 20 integers representing the sequence of notes. The last line contains the remainder of the notes, potentially fewer than 20.

SAMPLE INPUT (file theme.in)

30
25 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 18
82 78 74 70 66 67 64 60 65 80

OUTPUT FORMAT

The output file should contain a single line with a single integer that represents the length of the longest theme. If there are no themes, output 0.

SAMPLE OUTPUT (file theme.out)

5

[The five-long theme is the last five notes of the first line and the first five notes of the second] 

——————————————————————————————题解

这个的话我根本没有算我的算法的复杂度……

但是最慢是0.163

好像nocow里众说纷纭……我也因为复杂度算不好迟不迟不敢开敲

后来瞅了一眼他们说n^4加上几个优化就过了

那我怕个毛啊

我的思路是这样的,既然作曲家喜欢奇怪的转调,那么其实这些主旋律的差值都是一样的,这样处理成差分就可以了,为了让差分都是正值我们可以都加上88

然后hash存起来,类似Rabin-Karp字符串匹配的哈希函数

然后用200个vector来记录每个值在的位置,n^2的枚举然后二分长度更新ans

二分时的优化,如果r<=ans 跳出

  1 /*
  2 ID: ivorysi
  3 LANG: C++
  4 TASK: theme
  5 */
  6 #include <iostream>
  7 #include <cstdio>
  8 #include <cstring>
  9 #include <algorithm>
 10 #include <queue>
 11 #include <set>
 12 #include <vector>
 13 #include <string.h>
 14 #define siji(i,x,y) for(int i=(x);i<=(y);++i)
 15 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
 16 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
 17 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
 18 #define inf 0x7fffffff
 19 #define ivorysi
 20 #define mo 97797977
 21 #define hash 974711
 22 #define base 47
 23 #define pss pair<string,string>
 24 #define MAXN 5000
 25 #define fi first
 26 #define se second
 27 #define pii pair<int,int>
 28 typedef long long ll;
 29 using namespace std;
 30 int h[5005];
 31 int e[5005];
 32 int num[5005],n,lis[5005],f[5005],ans;
 33 vector<int> v[200];
 34 bool check(int s1,int s2,int len) {
 35     if(s1+len > n+1 || s2+len > n+1) return false;
 36     return ((ll)e[MAXN-s1]*(h[s1+len-1]-h[s1-1])-(ll)e[MAXN-s2]*(h[s2+len-1]-h[s2-1]))%mo==0;
 37 } 
 38 void init() {
 39     scanf("%d",&n);
 40     siji(i,1,n) {
 41         scanf("%d",&num[i]);
 42     }
 43     --n;
 44     siji(i,1,n) {
 45         lis[i]=num[i+1]-num[i]+88;
 46         v[lis[i]].push_back(i);
 47     }
 48     siji(i,0,180) {
 49         if(!v[i].empty()) {
 50             sort(v[i].begin(),v[i].end());
 51         }
 52     }
 53     e[0]=1;
 54     siji(i,1,5000) {
 55         e[i]=(ll)e[i-1]*base%mo;
 56     }
 57     siji(i,1,n) {
 58         h[i]=((ll)h[i-1]+(ll)lis[i]*e[i]%mo)%mo;
 59     }
 60 }
 61 int binary(int s1,int s2,int minz,int maxz) {
 62     if(maxz<=minz) return -1;
 63     if(maxz<=ans) return -1;
 64     int l=minz,r=maxz;
 65     while(l<r) {
 66         int mid=(l+r+1)>>1;
 67         if(check(s1,s2,mid)) l=mid;
 68         else {
 69             r=mid-1;
 70             if(r<=ans) return -1;
 71         }
 72     }
 73     return l;
 74 }
 75 void solve() {
 76     init();
 77     siji(i,0,180) {
 78         if(v[i].empty() || v[i].size()==1) continue;
 79         xiaosiji(j,0,v[i].size()) {
 80             if(f[v[i][j]-1]>=2) f[v[i][j]]=f[v[i][j]-1]-1;
 81             else f[v[i][j]]=1;
 82             xiaosiji(k,j+1,v[i].size()) {
 83                 int x=binary(v[i][j],v[i][k],f[v[i][j]],v[i][k]-v[i][j]-1);
 84                 f[v[i][j]]=max(f[v[i][j]],x);
 85                 f[v[i][k]]=max(f[v[i][k]],x);
 86             }
 87             ans=max(ans,f[v[i][j]]);
 88         }
 89     }
 90     ++ans;
 91     if(ans<5) puts("0");
 92     else {
 93         printf("%d\n",ans);
 94     }
 95 } 
 96 int main(int argc, char const *argv[])
 97 {
 98 #ifdef ivorysi
 99     freopen("theme.in","r",stdin);
100     freopen("theme.out","w",stdout);
101 #else
102     freopen("f1.in","r",stdin);
103 #endif
104     solve();
105     return 0;
106 }

 

USACO 5.1 Musical Themes(哈希+二分)