zoukankan      html  css  js  c++  java
  • 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
    ",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 }
  • 相关阅读:
    faked 一个用于 mock 后端 API 的轻量工具
    分享开源 Markdown 编辑器 Mditor 的「桌面版」
    一个 MVC 框架以 MVVM 之「魂」复活了!
    简单的内存缓存模块
    Node 多进程并发控制小模块
    Confman
    用 Nokitjs 解决前端开发中的跨域问题
    LEK分布式日志系统搭建
    hello world2
    hello world!
  • 原文地址:https://www.cnblogs.com/ivorysi/p/6371845.html
Copyright © 2011-2022 走看看