冲刺国赛模拟 36
感觉思想都不难,但是场上不是想不出来就是写不动,见了鬼了。
染色题
考虑一个转化:对于奇数位置,在
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
const int mod=998244353;
int n,m,dp[1000010],sum1[1000010],sum2[1000010],a[1000010];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)a[i]=i;
for(int i=1;i<=m;i++){
int l,r;scanf("%d%d",&l,&r);
if(r>=2)a[r-2]=min(a[r-2],l);
}
for(int i=n-1;i>=1;i--)a[i]=min(a[i],a[i+1]);
dp[0]=sum2[0]=1;
for(int i=1;i<=n;i++){
if(i&1){
dp[i]=(sum1[i-1]+sum2[a[i]-1])%mod;
sum1[i]=(sum1[i-1]+dp[i])%mod;
sum2[i]=sum2[i-1];
}
else{
dp[i]=(sum2[i-1]+sum1[a[i]-1])%mod;
sum1[i]=sum1[i-1];
sum2[i]=(sum2[i-1]+dp[i])%mod;
}
}
int ans=0;
for(int i=0;i<=n;i++)ans=(ans+dp[i])%mod;
ans=2ll*ans%mod;
printf("%d\n",ans);
}
石头剪刀布
先考虑标准淘汰赛的过程怎么处理:设
然后考虑设
现在考虑回答询问。容易发现一个区间可以拆成
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <unordered_map>
using namespace std;
const int mod=998244353,inv3=(mod+1)/3;
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
int n,m,trans[3][3],a[300010];
char s[300010];
struct node{
int a[3];
node(){memset(a,0,sizeof(a));}
node operator+(const node&s)const{
node ans;
for(int i=0;i<=2;i++)ans.a[i]=(a[i]+s.a[i])%mod;
return ans;
}
node operator*(const node&s)const{
node ans;
for(int i=0;i<=2;i++){
for(int j=0;j<=2;j++){
ans.a[i]=(ans.a[i]+1ll*a[i]*s.a[j]%mod*trans[i][j])%mod;
if(i==j)continue;
ans.a[j]=(ans.a[j]+1ll*a[i]*s.a[j]%mod*trans[j][i])%mod;
}
}
return ans;
}
}val[3],f[300010][20],g[300010][20];
node query(int L,int R,int l,int r){
if(l<=L&&R<=r)return g[L][__lg(R-L+2)];
int mid=(L+R)>>1;
node val;
if(l<=mid)val=val+f[mid][__lg(R-mid+1)]*query(L,mid-1,l,r);
if(mid<r)val=val+f[L][__lg(mid-L+1)]*query(mid+1,R,l,r);
return val;
}
int main(){
scanf("%d%d%s",&n,&m,s+1);
for(int i=1;i<=n;i++){
if(s[i]=='R')a[i]=0;
if(s[i]=='P')a[i]=1;
if(s[i]=='S')a[i]=2;
}
trans[0][0]=trans[1][1]=trans[2][2]=1;
trans[0][1]=trans[1][2]=inv3;trans[0][2]=inv3<<1;
trans[1][0]=trans[2][1]=inv3<<1;trans[2][0]=inv3;
val[0].a[0]=val[1].a[1]=val[2].a[2]=1;
for(int i=1;i<=n;i++)f[i][0]=g[i][1]=val[a[i]];
for(int j=1;j<=__lg(n)+1;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
f[i][j]=f[i][j-1]*f[i+(1<<j-1)][j-1];
}
}
for(int j=2;j<=__lg(n)+1;j++){
for(int i=1;i+(1<<j)-2<=n;i++){
g[i][j]=g[i][j-1]*f[i+(1<<j-1)-1][j-1]+f[i][j-1]*g[i+(1<<j-1)][j-1];
}
}
while(m--){
int l,r,x,y;scanf("%d%d%d%d",&l,&r,&x,&y);
int ans=query(l,r,x,y).a[0];
if(x-l&1)x++;
ans=1ll*ans*qpow((y-x>>1)+1,mod-2)%mod;
printf("%d\n",ans);
}
return 0;
}
树状数组
首先考虑关键性质:减个 lowbit 之后比 lowbit 低的所有位都变成
但是这题难度基本全在怎么写。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <unordered_map>
using namespace std;
int n,m,k,A,B;
int nxt[500010][31][2],val[500010],a[500010],ans[500010];
int lowbit(int x){
return x&-x;
}
int query(int l,int r){
return val[r]^val[l-1];
}
void calc(int d){
nxt[n+1][d][0]=n+1;
for(int i=n;i>=1;i--){
if(a[i]==-1)nxt[i][d][0]=nxt[i][d][1]=i+1;
else{
if(nxt[i][d-1][0]){
if((query(i,nxt[i][d-1][0]-1)>>d)&1){
nxt[i][d][0]=nxt[nxt[i][d-1][0]][d][1];
nxt[i][d][1]=nxt[i][d-1][0];
}
else{
nxt[i][d][0]=nxt[i][d-1][0];
nxt[i][d][1]=nxt[nxt[i][d-1][0]][d][1];
}
}
}
}
}
int find(int x){
const int U=(1<<k)-1;
for(int i=k-1;i>=0;i--){
if(nxt[x][i][0]){
int ss=(1<<i+1)-1;ss=U^ss;
return (query(x,n)&ss)|(ans[nxt[x][i][0]]&(U^ss));
}
}
return query(x,n);
}
int lastans;
int getans(int pos,int x){
const int U=(1<<k)-1;
for(int i=0;i<k;i++){
if((x>>i)&1){
if(!nxt[pos][i][1]){
int ss=(1<<i)-1;ss=U^ss;
return ((x^query(pos,n))&ss)|(ans[pos]&(U^ss));
}
int ss=(1<<i+1)-1;ss=U^ss;
x^=query(pos,nxt[pos][i][1]-1)&ss;
x-=lowbit(x);
pos=nxt[pos][i][1];
}
}
return ans[pos];
}
int main(){
scanf("%d%d%d%d%d",&n,&m,&k,&A,&B);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
if(a[i]==-1)val[i]=val[i-1];
else val[i]=val[i-1]^a[i];
}
nxt[n+1][0][0]=n+1;
for(int i=n;i>=1;i--){
if(a[i]==-1)nxt[i][0][0]=nxt[i][0][1]=i+1;
else if(a[i]&1){
nxt[i][0][0]=nxt[i+1][0][1];
nxt[i][0][1]=i+1;
}
else{
nxt[i][0][0]=i+1;
nxt[i][0][1]=nxt[i+1][0][1];
}
}
for(int i=1;i<k;i++)calc(i);
for(int i=n;i>=1;i--)ans[i]=find(i);
while(m--){
int l,x;scanf("%d%d",&l,&x);
l=l^((1ll*A*lastans+B)%n);x=x^((1ll*A*lastans+B)&((1<<k)-1));
printf("%d\n",lastans=getans(l,x));
}
return 0;
}
快踩
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】