9.15 比赛总结
突然想起来自己把比赛总结的好习惯忘掉了,所以现在重新拾起,故名曰《朝花夕拾》。
T1 出了个大阴间题
看数据范围明显状压。很明显,\(a,b\) 分成两部分处理。
\(f_{s,i}\) 表示状态为 \(s\),\(a=i\) 时的所有情况之和,还要计算 \(num_{s,i}\) 表示此时情况数。
\(b\) 直接递推模拟即可,时间复杂度 \(O(2^nn^2)\),拿下最劣解。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M=1<<18,p=1e9+7;
int n,m,k,s,a[20],b[100];
int f[M][100],num[M][100];
unordered_map<int,int>mp;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>k;int ans=0,bb=0;
for(int i=1;i<n;i++)
ans=(ans+bb)%p,bb=(2*bb+1)%p;
for(int i=1;i<=n;i++){
cin>>a[i];
if(!mp[a[i]])
mp[a[i]]=1,b[++m]=a[i];
if(!mp[a[i]+1])
mp[a[i]+1]=1,b[++m]=a[i]+1;
}sort(b+1,b+m+1);
for(int i=1;i<=m;i++) mp[b[i]]=i;
for(int i=1;i<=n;i++) a[i]=mp[a[i]];
for(int i=1;i<=n;i++)
num[(1<<i)>>1][a[i]]=1;
int mx=(1<<n)-1;
for(int i=1;i<=mx;i++)
for(int j=1;j<=m;j++){
if(!num[i][j]) continue;
for(int l=1;l<=n;l++)
if(!(((1<<l)>>1)&i)){
int S=i|((1<<l)>>1);
int r=(a[l]==j)?j+1:max(a[l],j);
f[S][r]=(f[S][r]+f[i][j]+k*b[r]%p*num[i][j])%p;
num[S][r]=(num[S][r]+num[i][j])%p;
}
}
s=(!num[mx][m])?m-1:m;
cout<<b[s]<<" "<<(f[mx][s]+ans*num[mx][s])%p;
return 0;
}
T2 最简单辣快来做
T3 是我的你不要抢
很容易想到用哈希进行判断,同时为了避免不必要的重复计算,我们用 \(unordered\_map\) 存储已经计算过的答案。写得好可以拿 \(99pts\)。
实际上99分做法挂的原因不是因为做法正确性,而是因为哈希冲突。
我们都知道,哈希冲突是指不一样的字符串,哈希值相同。通常我们用 \(unsigned\ long\ long\) 就可以了,但这道题卡这种哈希,所以我们就可以用 \(998244353\) 作为模数也验证一遍即可。
\(unsigned\ long\ long\) 时间复杂度比较小,所以要放在前面,防止大量问题堆积在 \(get\) 中的第二个 \(if\) 中,导致常数爆炸。(实测,\(ull\ WA,998244353\ TLE\))
下面证明 \(hash\) 时间复杂度正确:
设有 \(x\) 个字符串,\(n=\sum |a_i|\),则时间复杂度为 \(O(nx)(x^2\le q)\) 或 \(O(\frac{nq}{x})(x^2>q)\)
两个式子最大值都是 \(O(n\sqrt q)\),常数很小,可以卡过。
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define uint unsigned int
using namespace std;
const int M=6e5+5;
const int p=998244353;
const ull q=1145141;
const int qq=19198101;
int z(char c){
return c-'a';
}vector<ull>hs[M];
vector<int>hh[M];
string s;ull qp[M];
int n,m,l[M],pq[M];
unordered_map<int,int>mp[M];
int get(int i,int j){
for(int k=min(l[i],l[j]);k;k--)
if(hs[i][l[i]]-hs[i][l[i]-k]*qp[k]==hs[j][k])
if((hh[i][l[i]]-(ll)hh[i][l[i]-k]*pq[k]%p+p)%p==hh[j][k]) return k;
return 0;
}signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m,qp[0]=pq[0]=1;
for(int i=1;i<=n;i++){
cin>>s,s=" "+s;
l[i]=s.size()-1;
hs[i].push_back(0);
for(int j=1;j<=l[i];j++)
hs[i].push_back(hs[i][j-1]*q+z(s[j]));
hh[i].push_back(0);
for(int j=1;j<=l[i];j++)
hh[i].push_back(((ll)hh[i][j-1]*qq%p+z(s[j]))%p);
}for(int i=1;i<M;i++)
qp[i]=qp[i-1]*q,pq[i]=(ll)pq[i-1]*qq%p;
while(m--){
int x,y;cin>>x>>y;
if(!mp[x].count(y))
mp[x][y]=get(x,y);
cout<<mp[x][y]<<"\n";
}return 0;
}