zoukankan      html  css  js  c++  java
  • 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\) 满足,

    1. \(y - k\)\(y + k\) 互质。
    2. \(y - k \in [L, R]\)
    3. \(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的代码,我没写。

    本欲起身离红尘,奈何影子落人间。
  • 相关阅读:
    C# 开发Chrome内核浏览器(WebKit.net)
    SQL 存储过程语句拼接愁人的时间类型
    Linux简介
    揭秘Node.js深受欢迎的原因
    6个强大的AngularJS扩展应用
    ElasticSearch NEST
    web中的各种打印方案
    配置问题总结
    leetcode -day29 Binary Tree Inorder Traversal &amp; Restore IP Addresses
    HBase高速导入数据--BulkLoad
  • 原文地址:https://www.cnblogs.com/jcgf/p/15310790.html
Copyright © 2011-2022 走看看