1 条题解

  • 0
    @ 2025-10-14 16:40:31

    对每个技能的提升次数做前缀和,这样对每同一天的所有技能提升次数打包起来就是一个状态,由于需要的信息是同一天内所有技能提升次数之间的相互关系(两两之间的差值)而不是他们的实际大小,所以所有技能提升次数都减掉最后一个技能的提升次数再打包作为状态。

    (题外话:学过乐理的应该都知道首调和固定调,我们这里要判断两个旋律是否是一样的,就不是拿固定调而是首调的谱来对比,不是要看准确音高吻合而是要看音程关系吻合。假设所有旋律都是大调、结尾都是主音,那么所有音高减去主音音高再加1,主音变成 C,就可以方便地对比了)

    具体来说,比如某天升级完,几个技能总提升次数分别为 1 1 4,之后到某一天变成了 5 5 8,这俩相减就知道这中间所有技能升级次数一样多,显然这两天的两两之间的差值也是吻合的,按上面的处理之后都会变成 -3 -3 0,就方便统计答案了。

    处理之后对每天的状态都找到之前最早跟这个状态相同的日子,更新答案。

    这个题会卡哈希,建议双哈希,肯定不会被卡。

    有用 vector 当状态的办法,代码更简单,这里不提供了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll p=13331,q=131,md1=998244353,md2=1e9+7;
    int n,m,a[100005],b[100005][35],ans,cnt[100005];
    ll d[100],d2[100];
    map<pair<int,int>,int>mp1,mp2;
    int main(){
    	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    		for(int j=0;j<m;j++)b[i][j]=(a[i]>>j&1)+b[i-1][j];
    	}
    	d[0]=d2[0]=1;
    	for(int i=1;i<m;i++)d[i]=d[i-1]*p%md1,d2[i]=d2[i-1]*q%md2;
    	for(int i=0;i<=n;i++){
    		int c1=0,c2=0;
    		if(i>0)for(int j=0;j<m;j++)b[i][j]-=b[i][m-1],c1+=1ll*b[i][j]*d[j]%md1,c2+=1ll*b[i][j]*d2[j]%md2;
    		if(!mp1[{c1,c2}])mp1[{c1,c2}]=(i==0?-1:i);
    		else{
    			mp2[{c1,c2}]=i;
    			ans=max(ans,mp2[{c1,c2}]-(mp1[{c1,c2}]==-1?0:mp1[{c1,c2}]));
    		}
    	}
    	cout<<ans;
    	return 0;
    } 
    
    • 1

    信息

    ID
    1858
    时间
    1000ms
    内存
    128MiB
    难度
    8
    标签
    递交数
    14
    已通过
    9
    上传者