1.给出8个函数f(a,b,c)=k,其中a,b,c,k均为一个bool。对于一个长度为奇数的 零 一 字符串,我们称之为好的,当且仅当存在一种操作方法,使得这个字符串能变为1:
1.选出一个奇数i。令S=str[1,i],T=str[i+1,n]
2.从右往左将末尾3个数字替换为f(a,b,c)。直到S长度为1。
3.str=S+T
现在字符串中有一些问号,问有多少种将问号替换为0或1的不同的方案,使得这个字符串是好的。
我们考虑对于一个字符串,如何线性判断是不是好的。显然整个过程可以看成是一个栈的进入和弹出,而一个栈的实际影响相当于函数G[a,b](x),表示若x=0,返回a,否则返回b。
每次新加入两个数,要么是直接塞入栈中,更新函数。要么是先加入一个数,获得返回值之后加入另一个数,更新函数。
不同的G只有4个,将这个过程变为dp的状态即可计数。
1 #define mod 998244353 2 #include<bits/stdc++.h> 3 using namespace std; 4 typedef long long int ll; 5 const int maxn=1E6+5; 6 string str; 7 int n; 8 int c[2][2][2]; 9 int a[maxn]; 10 int to[4][4],what[2][2],out[4][2]; 11 ll f[maxn][17]; 12 inline void add(ll&x,ll y) 13 { 14 x=(x+y)%mod; 15 } 16 inline void solve() 17 { 18 string x; 19 cin>>x; 20 c[0][0][0]=x[0]-'0'; 21 c[1][0][0]=x[1]-'0'; 22 c[0][1][0]=x[2]-'0'; 23 c[1][1][0]=x[3]-'0'; 24 c[0][0][1]=x[4]-'0'; 25 c[1][0][1]=x[5]-'0'; 26 c[0][1][1]=x[6]-'0'; 27 c[1][1][1]=x[7]-'0'; 28 cin>>str; 29 n=str.size(); 30 str="!"+str; 31 for(int i=1;i<=n;++i) 32 a[i]=str[i]-'0'; 33 for(int a1=0;a1<=1;++a1) 34 for(int b1=0;b1<=1;++b1) 35 for(int a2=0;a2<=1;++a2) 36 for(int b2=0;b2<=1;++b2) 37 { 38 if(a2==0&&b2==0) 39 to[a1+b1*2][a2+b2*2]=a1+a1*2; 40 if(a2==0&&b2==1) 41 to[a1+b1*2][a2+b2*2]=a1+b1*2; 42 if(a2==1&&b2==0) 43 to[a1+b1*2][a2+b2*2]=b1+a1*2; 44 if(a2==1&&b2==1) 45 to[a1+b1*2][a2+b2*2]=b1+b1*2; 46 out[a1+b1*2][0]=a1; 47 out[a1+b1*2][1]=b1; 48 } 49 for(int i=0;i<=1;++i) 50 for(int j=0;j<=1;++j) 51 { 52 int x=c[i][j][0],y=c[i][j][1]; 53 what[i][j]=x+y*2; 54 } 55 memset(f,0,sizeof(f)); 56 f[0][1<<2]=1; 57 for(int i=0;i<n-1;i+=2) 58 for(int i1=0;i1<=1;++i1) 59 for(int i2=0;i2<=1;++i2) 60 { 61 if(a[i+1]!='?'-'0'&&i1!=a[i+1]) 62 continue; 63 if(a[i+2]!='?'-'0'&&i2!=a[i+2]) 64 continue; 65 int num=what[i1][i2]; 66 for(int S=0;S<(1<<4);++S) 67 { 68 if(!f[i][S]) 69 continue; 70 int nS=0; 71 for(int k=0;k<4;++k) 72 if(S&(1<<k)) 73 { 74 nS|=1<<to[k][num]; 75 nS|=1<<what[out[k][i1]][i2]; 76 } 77 add(f[i+2][nS],f[i][S]); 78 } 79 } 80 ll ans=0; 81 for(int i=0;i<=1;++i) 82 { 83 if(a[n]!='?'-'0'&&i!=a[n]) 84 continue; 85 for(int S=0;S<(1<<4);++S) 86 for(int k=0;k<4;++k) 87 if((S&(1<<k))&&out[k][i]==1) 88 { 89 add(ans,f[n-1][S]); 90 break; 91 } 92 } 93 cout<<ans<<endl; 94 } 95 int main() 96 { 97 freopen("junior.in","r",stdin); 98 freopen("junior.out","w",stdout); 99 ios::sync_with_stdio(false); 100 int T; 101 cin>>T; 102 while(T--) 103 solve(); 104 return 0; 105 }
2.一个序列,每次询问一个区间,问这个区间中所有子区间的gcd的乘积。
注意到一个区间gcd变换到1的总次数不会超过log次,我们首先找到这个区间以及它的gcd的值。之后离线,一个询问可以看成是二维平面中的矩形的元素乘积,而且他们都是紧贴上边界的。
复杂度O(nlogn^2)。
1 #pragma GCC optimize 2 2 #define mod 998244353 3 #include<bits/stdc++.h> 4 using namespace std; 5 typedef long long int ll; 6 const int maxn=4E5+5; 7 int n,m,a[maxn]; 8 ll ans[maxn]; 9 inline int read() 10 { 11 char ch=getchar(); 12 while(!isdigit(ch))ch=getchar(); 13 int s=ch-'0';ch=getchar(); 14 while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();} 15 return s; 16 } 17 int G[55]; 18 inline void write(int x) 19 { 20 int g=0; 21 do{G[++g]=x%10;x/=10;}while(x); 22 for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n'); 23 } 24 int gcd(int x,int y) 25 { 26 return x%y==0?y:gcd(y,x%y); 27 } 28 inline ll qpow(ll x,int y) 29 { 30 ll ans=1,base=x; 31 while(y) 32 { 33 if(y&1) 34 ans=ans*base%mod; 35 base=base*base%mod; 36 y>>=1; 37 } 38 return ans; 39 } 40 ll t[maxn*4],tag[maxn*4]; 41 void build(int l,int r,int num) 42 { 43 tag[num]=t[num]=1; 44 if(l==r) 45 return; 46 int mid=(l+r)>>1; 47 build(l,mid,num<<1),build(mid+1,r,num<<1|1); 48 } 49 inline void putTag(int num,ll x,int len) 50 { 51 t[num]=t[num]*qpow(x,len)%mod; 52 tag[num<<1]=tag[num<<1]*x%mod; 53 tag[num<<1|1]=tag[num<<1|1]*x%mod; 54 } 55 inline void pushdown(int num,int len) 56 { 57 ll x=tag[num]; 58 tag[num]=1; 59 if(x==1) 60 return; 61 putTag(num,x,len); 62 } 63 inline void pushup(int num) 64 { 65 t[num]=t[num<<1]*t[num<<1|1]%mod; 66 } 67 void change(int L,int R,int l,int r,ll x,int num) 68 { 69 pushdown(num,r-l+1); 70 if(L<=l&&r<=R) 71 { 72 putTag(num,x,r-l+1); 73 return; 74 } 75 int mid=(l+r)>>1; 76 if(R<=mid) 77 change(L,R,l,mid,x,num<<1); 78 else if(mid<L) 79 change(L,R,mid+1,r,x,num<<1|1); 80 else 81 change(L,R,l,mid,x,num<<1),change(L,R,mid+1,r,x,num<<1|1); 82 pushup(num); 83 } 84 ll ask(int L,int R,int l,int r,int num) 85 { 86 pushdown(num,r-l+1); 87 if(L<=l&&r<=R) 88 return t[num]; 89 int mid=(l+r)>>1; 90 if(R<=mid) 91 return ask(L,R,l,mid,num<<1); 92 else if(mid<L) 93 return ask(L,R,mid+1,r,num<<1|1); 94 return ask(L,R,l,mid,num<<1)*ask(L,R,mid+1,r,num<<1|1)%mod; 95 } 96 struct line 97 { 98 int l,r,x; 99 line(int a=0,int b=0,int c=0):l(a),r(b),x(c){} 100 }S[maxn]; 101 int tot; 102 struct query 103 { 104 int x,l,r,id,type; 105 bool operator<(const query&A)const 106 { 107 return x>A.x; 108 } 109 }Q[maxn*2]; 110 void out(int l,int r,int num) 111 { 112 pushdown(num,r-l+1); 113 if(l==r) 114 { 115 cout<<t[num]<<" "; 116 return; 117 } 118 int mid=(l+r)>>1; 119 out(l,mid,num<<1),out(mid+1,r,num<<1|1); 120 } 121 inline void solve() 122 { 123 sort(Q+1,Q+tot+1); 124 build(1,n,1); 125 int top=0; 126 int pos=1; 127 while(Q[pos].x==n+1) 128 ++pos; 129 for(int i=n;i>=1;--i) 130 { 131 S[++top]=line(i,i,a[i]); 132 for(int j=top-1;j>=1;--j) 133 { 134 S[j].x=gcd(S[j].x,S[j+1].x); 135 if(S[j].x==S[j+1].x) 136 { 137 S[j].l=S[j+1].l; 138 for(int k=j+1;k<=top;++k) 139 S[k]=S[k+1]; 140 --top; 141 } 142 } 143 for(int i=1;i<=top;++i) 144 change(S[i].l,S[i].r,1,n,S[i].x,1); 145 while(Q[pos].x==i) 146 { 147 int id=Q[pos].id; 148 if(Q[pos].type) 149 ans[id]=ans[id]*qpow(ask(Q[pos].l,Q[pos].r,1,n,1),mod-2)%mod; 150 else 151 ans[id]=ans[id]*ask(Q[pos].l,Q[pos].r,1,n,1)%mod; 152 ++pos; 153 } 154 } 155 } 156 int main() 157 { 158 freopen("easy.in","r",stdin); 159 freopen("easy.out","w",stdout); 160 ios::sync_with_stdio(false); 161 n=read(),m=read(); 162 for(int i=1;i<=n;++i) 163 a[i]=read(); 164 for(int i=1;i<=m;++i) 165 { 166 ++tot; 167 Q[tot].l=read(),Q[tot].r=read(); 168 Q[tot].id=i; 169 Q[tot].type=0; 170 Q[tot].x=Q[tot].l; 171 ++tot; 172 Q[tot]=Q[tot-1]; 173 Q[tot].type=1; 174 Q[tot].x=Q[tot].r+1; 175 ans[i]=1; 176 } 177 solve(); 178 for(int i=1;i<=m;++i) 179 write(ans[i]); 180 return 0; 181 }