20240718【提高】模拟

怎么又没过 T1 啊,怎么想的啊?为啥我就不能把贡献拆开算呢?这他妈不是很显然吗???

并不认为这是提高模拟。

T1

首先考虑将括号序列暴力建出来,这时的做法是显然的,考虑用一种类似于 dp 的转移,记 wi 表示以 i 为右端的合法括号序列能和前面多少个合法括号序列相连,这样我们先对括号序列进行匹配,令右括号 i 对应的左括号为 j,那么转移就是 w[i]=w[j1],最后答案是匹配的左右括号对数加上所有右括号的 wi

一段前后拼接的合法括号序列所产生的贡献就是 i=lrwi,不用把贡献留到最后一位算 len(len+1)/2,这就是我错的最主要的地方。

然后考虑将上述算法扩展成正解。因为一个位置有多个右括号,所以我们需要不断地去匹配,知道右括号不够或者刚好匹配玩一个点的左括号。当能够恰好匹配完一个点 j 的左括号时,这个点 i 就可以从 j1 的右括号转移过来,但是注意一个点有很多个右括号,但只能有一次转移并算贡献,所以还要开一个数组记录。如果右括号匹配完了那么这个点就可以对后面的点产生贡献,就 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暴力。

除了爆搜,第一应该想到是一个 O(n4) 的做法。但是直接枚举四个数不太能转移计数,那么考虑 dp,设 dpi,x,y,z 表示前 i 个数中最后三个选的数是 x,y,z 时的方案数,转移的话就枚举下一个数取不取并且是否合法就行了。

考虑压缩状态,设 dpx,y,z 表示最后三个数取的是 x,y,z 时的方案数。对于一般情况有转移:dp[x][y][z]=i<z,ai=axayazsdp[y][z][i] 对于求和号部分可以考虑开一个数组维护,这样转移就是 O(1) 的,总时间复杂度 O(n3+2mn),能过60pts。

然后考虑发掘一些性质(?),由于 ai 互不相同,可以发现对于子序列中的连续五个元素,若前四个异或和为 s,那么后四个异或和一定不为 s,这个结论显然。那么我们就可以再压缩一次状态,设 dpx,y 为最后两个数取 x,y 时的方案数,那么有转移:dp[x][y]=z<y(f[y][z]i<z,aiaxayaz=sdp[z][i])
可以拆成:dp[x][y]=z<ydp[y][z]i<z<y,aiaxayaz=sdp[z][i])
右边式子两部分都可以新开数组维护,总复杂度 O(n(n+2m)),可过。

不过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;
} 
posted @   和蜀玩  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示