20240718【提高】模拟
怎么又没过 T1 啊,怎么想的啊?为啥我就不能把贡献拆开算呢?这他妈不是很显然吗???
并不认为这是提高模拟。
T1
首先考虑将括号序列暴力建出来,这时的做法是显然的,考虑用一种类似于 dp 的转移,记 表示以 为右端的合法括号序列能和前面多少个合法括号序列相连,这样我们先对括号序列进行匹配,令右括号 对应的左括号为 ,那么转移就是 ,最后答案是匹配的左右括号对数加上所有右括号的 。
一段前后拼接的合法括号序列所产生的贡献就是 ,不用把贡献留到最后一位算 ,这就是我错的最主要的地方。
然后考虑将上述算法扩展成正解。因为一个位置有多个右括号,所以我们需要不断地去匹配,知道右括号不够或者刚好匹配玩一个点的左括号。当能够恰好匹配完一个点 的左括号时,这个点 就可以从 的右括号转移过来,但是注意一个点有很多个右括号,但只能有一次转移并算贡献,所以还要开一个数组记录。如果右括号匹配完了那么这个点就可以对后面的点产生贡献,就 w_i++
。
实际上真的很简单,但我就是傻逼,乆乆乆。
还有取模是骗人的。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pi pair<ll,ll>
#define fi first
#define se second
const ll N=10000005,M=1919810;
ll n,x,y,z,m0,m1,c[N];
ll cnt,tot,w[N],ans;
bool f[N];
pi a[N];
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>x>>y>>z>>m0>>m1>>c[0]>>c[1];
for(int i=2;i<n;++i){
ll m=((i&1)?m1:m0);
c[i]=(c[i-1]*x+c[i-2]*y+z)%m+1;
}
for(int i=0;i<n;++i){
if(i%2==0) a[++cnt]={i,c[i]};
else{
while(c[i]&&cnt){
pi x=a[cnt]; --cnt;
if(x.se==c[i]) w[i]+=w[x.fi-1];
if(x.se<=c[i]){
c[i]-=x.se;
ans+=x.se;
if(x.se>0) ans+=(f[x.fi-1]==0)*w[x.fi-1];
}
else{
ans+=c[i];
x.se-=c[i],c[i]=0;
a[++cnt]=x;
}
}
if(c[i]){
cnt=0;
f[i]=1,w[i]=0;
}
else ++w[i];
}
}
cout<<ans;
return 0;
}//乆乆乆乆乆乆乆乆乆乆乆乆乆乆乆乆乆乆乆乆乆乆
//一步错误的思路葬送了我,为甚么我就不能把贡献拆开来算呢?????!!!!!
T2
只花了10min打了15pts暴力。
除了爆搜,第一应该想到是一个 的做法。但是直接枚举四个数不太能转移计数,那么考虑 dp,设 表示前 个数中最后三个选的数是 时的方案数,转移的话就枚举下一个数取不取并且是否合法就行了。
考虑压缩状态,设 表示最后三个数取的是 时的方案数。对于一般情况有转移: 对于求和号部分可以考虑开一个数组维护,这样转移就是 的,总时间复杂度 ,能过60pts。
然后考虑发掘一些性质(?),由于 互不相同,可以发现对于子序列中的连续五个元素,若前四个异或和为 ,那么后四个异或和一定不为 ,这个结论显然。那么我们就可以再压缩一次状态,设 为最后两个数取 时的方案数,那么有转移:
可以拆成:
右边式子两部分都可以新开数组维护,总复杂度 ,可过。
不过std代码咋和题解不一样啊,不过也就状态不一样。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=4097,M=1919810,mod=998244353;
ll n,m,s,a[N],ans=0;
ll dp[N][N],f[N],g[N];
//这题解代码咋还和题解讲得不一样?
int main(){
//freopen("school.in","r",stdin);
//freopen("school.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m>>s;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i){
for(int j=1;j<i;++j){
f[a[j]]=((g[j]+1-dp[j-1][a[i]^a[j]^s])%mod+mod)%mod;
g[i]=(g[i]+f[a[j]])%mod;
}
for(int j=1;j<=(1<<m);++j) dp[i][j]=(dp[i-1][j]+f[a[i]^j])%mod;
ans=(ans+g[i])%mod;
}
cout<<(ans+n)%mod;
return 0;
}