2021.09.18 膜你赛
2021.09.18 膜你赛
据说是老吕从三区偷的题。
zero
Description
给出一个长度为 \(n\) 的操作序列。每个位置为 \(\&\),\(|\),^中的一个。\(\&\) 表示按位与,\(|\) 表示按位或,^ 表示按位异或。
定义一个长度为 \(n+1\) 的 \(01\) 数列(即该数列只包含 \(0\) 和 \(1\))是合法的,当且仅当将该操作序列插入这个长度为 \(n+1\) 的数列后,运算结果为 \(1\)。
具体的讲,如果给出的操作序列为 &|^,将其插入到序列 \(1010\) 中进行运算:\(1\&0|1\)^\(0=1\)。所以 \(1010\) 就是操作序列 &|^
的一个合法序列。现在你需要统计对于一个给定的操作序列,有多少个合法序列。
由于答案可能很大,你只需要输出答案对 \(10^9+7\) 取模后的结果。
Solution
挺简单的一道 dp 题。(我能想出来的应该都挺简单)。
设 \(f_{i,0/1}\) 表示当前进行到第 \(i\) 为,到当前为答案为 \(0/1\) 的方案数。转移也根据三种操作分类就好了。
\(f_{i,0}=(f_{i,0}+f_{i-1,0}\times 2+f_{i-1,1}) |s_i=\&\)
\(f_{i,1}=(f_{i,1}+f_{i-1,1})|s_i=\&\)
\(f_{i,0}=(f_{i,0}+f_{i-1,0})|s_i=|\)
\(f_{i,1}=(f_{i,1}+f_{i-1,0}+f_{i-1,1}\times 2)|s_i=|\)
\(f_{i,0}=(f_{i,0}+f_{i-1,1}+f_{i-1,0})|s_i=\)^
\(f_{i,1}=(f_{i,1}+f_{i-1,0}+f_{i-1,1})|s_i=\)^
Code
/*
* @Author: smyslenny
* @Date: 2021.09.
* @Title:
* @Main idea:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#define int long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)
using namespace std;
const int mod=1e9+7;
const int M=1e7+5;
int n,f[M][3];
int read()
{
int x=0,y=1;
char c=getchar();
while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
return y?x:-x;
}
char s[M];
signed main()
{
// freopen("zero.in","r",stdin);
// freopen("zero.out","w",stdout);
n=read();
scanf("%s",s+1);
f[0][1]=1,f[0][0]=1;
for(int i=1;i<=n;i++)
{
if(s[i]=='&')
{
f[i][0]=(f[i][0]+(f[i-1][0]*2%mod+f[i-1][1])%mod)%mod;
f[i][1]=(f[i][1]+f[i-1][1])%mod;
}
if(s[i]=='|')
{
f[i][0]=(f[i][0]+f[i-1][0])%mod;
f[i][1]=((f[i][1]+f[i-1][0])%mod+f[i-1][1]*2%mod)%mod;
}
if(s[i]=='^')
{
f[i][0]=((f[i][0]+f[i-1][1])%mod+f[i-1][0])%mod;
f[i][1]=((f[i][1]+f[i-1][0])%mod+f[i-1][1])%mod;
}
}
printf("%lld\n",f[n][1]%mod);
return 0;
}
/*
3
&|^
*/
prime
Description
给定参数 \(L\) \(R\) \(K\),需要计算有多少个 \(y\) 满足,
- \(y - k\) 与 \(y + k\) 互质。
- \(y - k \in [L, R]\)。
- \(y + k \in [L, R]\)。
你只需要输出答案对 \(10^9 + 7\) 取模后的结果。
Solution
先推出式子
\(\sum\limits_{i=l}^{R-2k}[\gcd(i,2k)=1]\)
因此我们只要在区间中找出与 \(2k\) 互质的数就好了。将 \(2k\) 进行质因数分解,遵循容斥定理奇加偶减,容斥就好了。
Code
/*
* @Author: smyslenny
* @Date: 2021.09.
* @Title:
* @Main idea:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#define int long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)
using namespace std;
const int mod=1e9+7;
const int M=1e7+5;
int l,r,k;
int read()
{
int x=0,y=1;
char c=getchar();
while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
return y?x:-x;
}
int Ans;
namespace substack1{
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
void main()
{
for(int i=l+k;i<=r-k;i++)
if(gcd(i-k,i+k)==1) Ans++;
printf("%lld\n",Ans);
}
}
namespace substack2{
int cnt,prime[M];
int solve(int x)
{
if(x==-1) return 0;
int sum=0;
for(int i=0,p=1,f=1;i<1<<cnt;i++,p=1,f=1)
{
for(int j=0;j<cnt;j++)
if(i>>j&1)
p=p*prime[j],f*=-1;
sum=sum+x/p*f;
}
return sum;
}
void main()
{
if(l+2*k>r) {printf("0\n");return;}
k<<=1,r-=k;
for(int i=2;i<=k;i++)
{
if(!(k%i))
{
prime[cnt++]=i;
while(!(k%i))
k/=i;
}
}
if(k!=1) prime[cnt++]=k;
printf("%lld\n",solve(r)-solve(l-1));
}
}
signed main()
{
// freopen("prime.in","r",stdin);
// freopen("prime.out","w",stdout);
l=read(),r=read(),k=read();
substack2::main();
return 0;
}
mex
Description
给出一个长度为 \(n\) 的序列 \(s\)。定义 \(f(l,r)\) 表示该序列中下标位于区间 \([l,r]\) 的数字构成的集合中没有出现的最小的数字。
你需要计算 \(\sum\limits_{i=1}^{n}\sum\limits_{r=l}^nf(l,r)\)。
Solution
先预处理出 \(1\sim i(1\le i\le n)\) 的 mex,还有当前位置的数出现的下一个位置,我们知道,这肯定是单调不降的,然后我们处理左端点变化的情况,我们发现,如果左端点的数字在后面的数列里有的话,那么 mex 就是不变的,否则更新 mex 区间 [i,j] 中比当前值大的值为当前值。
用线段树维护。
Code
/*
Source: mex
*/
#include<cstdio>
#define int long long
/*----------------------------------------------------------*/
const int B = 1e5 + 7;
const int INF = 0x3f3f3f3f;
/*----------------------------------------------------------*/
template <typename T> inline T Min(T x, T y) {return x < y ? x : y;}
template <typename T> inline T Max(T x, T y) {return x > y ? x : y;}
/*----------------------------------------------------------*/
int n, a[B], mex[B], cnt[B], K, pos[B], pre[B], ans;
/*----------------------------------------------------------*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
/*----------------------------------------------------------*/
namespace Seg {
#define ls(x) x << 1
#define rs(x) x << 1 | 1
#define len (t[p].r - t[p].l + 1)
#define mid (t[p].l + t[p].r >> 1)
struct node {
int l, r, sum, max, lzy;
node() {l = r = sum = max = 0; lzy = -1;}
} t[B << 2];
void push_up(int p) {t[p].sum = t[ls(p)].sum + t[rs(p)].sum; t[p].max = Max(t[ls(p)].max, t[rs(p)].max);}
void build(int p, int l, int r) {
t[p].l = l; t[p].r = r; if(l == r) {t[p].sum = t[p].max = mex[l]; return ;}
build(ls(p), l, mid); build(rs(p), mid + 1, r); push_up(p);
}
void f(int p, int k) {t[p].lzy = t[p].max = k; t[p].sum = k * len;}
void push_down(int p) {f(ls(p), t[p].lzy); f(rs(p), t[p].lzy); t[p].lzy = -1;}
void up_date(int p, int l, int r, int k) {
if(l <= t[p].l && t[p].r <= r) {f(p, k); return ;}
if(~t[p].lzy) push_down(p);
if(l <= mid) up_date(ls(p), l, r, k); if(r > mid) up_date(rs(p), l, r, k);
push_up(p);
}
int query(int p, int k) {
if(t[p].l == t[p].r) return t[p].l;
if(k < t[ls(p)].max) return query(ls(p), k); else return query(rs(p), k);
}
}
void Main() {
n = read(); mex[n + 1] = INF; pre[0] = n + 1;
for(int i = 1; i ^ n + 1; ++i) a[i] = read(), cnt[a[i]]++, pre[i] = n + 1;
for(int i = 0; i ^ n + 1; ++i) if(!cnt[i]) {K = i; break;}
for(int i = n; i; --i)
{
mex[i] = K; if(!--cnt[a[i]]) K = Min(K, a[i]);
pos[i] = pre[a[i]]; pre[a[i]] = i;
}
Seg::build(1, 1, n); ans = Seg::t[1].sum;
for(int i = 1; i ^ n + 1; ++i)
{
Seg::up_date(1, i, i, 0);
if(Seg::t[1].max > a[i])
{
int x = Seg::query(1, a[i]);
if(x < pos[i]) Seg::up_date(1, x, pos[i] - 1, a[i]);
}
ans += Seg::t[1].sum;
}
Print(ans);
}
/*----------------------------------------------------------*/
signed main() {Main(); return 0;}
这显然是BS的代码,我没写。