zoukankan      html  css  js  c++  java
  • LOJ2331 某位歌姬的故事 和 CF1327F AND Segments

    LOJ2331 某位歌姬的故事

    IA 是一名会唱歌的女孩子。

    IOI2018 就要来了,IA 决定给参赛选手们写一首歌,以表达美好的祝愿。这首歌一共有 (n) 个音符,第 (i) 个音符的音高为 (h_i)。IA 的音域是 (A),她只能唱出 (1sim A) 中的正整数音高。因此 (1le h_ile A)

    在写歌之前,IA 需要确定下这首歌的结构,于是她写下了 (Q​) 条限制,其中第 (i​) 条为:编号在 (l_i​)(r_i​) 之间的音符的最高音高为 (m_i​)。在确定了结构之后,她就可以开始写歌了。不过她还是想知道,一共有多少种可能的歌曲满足她的所有限制?她听说你还有 9 个月就要去 IOI 了,于是希望你帮她计算一下这个值。

    (Qleq 500)

    题解

    仓鼠《动态规划选讲》。

    (max_{l≤i≤r}{A_i} = h)等价于(∀l ≤ i ≤ r, A_i ≤ h)(∃l ≤ i ≤ r, A_i = h)

    求出每个点的上限(up_i)。可以发现,(∃l ≤ i ≤ r, A_i = h)(i)只能由上限(up_i = h)的点来贡献

    所以对于每个(h)的限制以及上限为(h)的点单独拿出来DP,满足每个限制区间中至少有一个点达到上限即可。

    时间复杂度(O(Q^3)),可以利用前缀和优化到(O(Q^2))

    CO int N=1e3+10;
    int m,n,A;
    vector<int> num,val;
    struct node {int l,r,m;} a[N];
    int len[N],lim[N];
    int t[N],l[N],f[N][N];
    
    int solve(int x){
    	int tot=0;
    	for(int i=1;i<(int)num.size();++i)if(lim[i]==x){
    		t[++tot]=i,l[tot]=0;
    		for(int j=0;j<=tot;++j) f[tot][j]=0;
    	}
    	for(int i=1;i<=n;++i)if(a[i].m==x){
    		if(!tot) return 0;
    		int L=lower_bound(t+1,t+tot+1,a[i].l)-t;
    		int R=lower_bound(t+1,t+tot+1,a[i].r)-t-1;
    		l[R]=max(l[R],L);
    	}
    	f[0][0]=1;
    	for(int i=1;i<=tot;++i){
    		int v1=fpow(x,len[t[i]]),v2=fpow(x-1,len[t[i]]);
    		for(int j=0;j<i;++j)if(f[i-1][j]){
    			if(j>=l[i]) f[i][j]=add(f[i][j],mul(f[i-1][j],v2));
    			f[i][i]=add(f[i][i],mul(f[i-1][j],add(v1,mod-v2)));
    		}
    	}
    	int ans=0;
    	for(int i=0;i<=tot;++i) ans=add(ans,f[tot][i]);
    	return ans;
    }
    void real_main(){
    	read(m),read(n),read(A);
    	num={1,m+1},val.clear();
    	for(int i=1;i<=n;++i){
    		read(a[i].l),read(a[i].r),read(a[i].m);
    		num.push_back(a[i].l),num.push_back(++a[i].r);
    		val.push_back(a[i].m);
    	}
    	sort(num.begin(),num.end());
    	num.erase(unique(num.begin(),num.end()),num.end());
    	sort(val.begin(),val.end());
    	val.erase(unique(val.begin(),val.end()),val.end());
    	for(int i=1;i<(int)num.size();++i) len[i]=num[i]-num[i-1];
    	for(int i=1;i<=n;++i){
    		a[i].l=lower_bound(num.begin(),num.end(),a[i].l)-num.begin()+1;
    		a[i].r=lower_bound(num.begin(),num.end(),a[i].r)-num.begin()+1;
    	}
    	for(int i=1;i<(int)num.size();++i) lim[i]=A+1;
    	for(int i=1;i<=n;++i)
    		for(int j=a[i].l;j<a[i].r;++j)
    			lim[j]=min(lim[j],a[i].m);
    	
    	int ans=1;
    	for(int i=1;i<=(int)val.size();++i){
    		ans=mul(ans,solve(val[i-1]));
    		if(ans==0) {puts("0"); return;}
    	}
    	for(int i=1;i<(int)num.size();++i)
    		if(lim[i]==A+1) ans=mul(ans,fpow(A,len[i]));
    	printf("%d
    ",ans);
    }
    int main(){
    	for(int T=read<int>();T--;) real_main();
    	return 0;
    }
    

    CF1327F AND Segments

    You are given three integers (n, k, m) and (m) conditions ((l_1, r_1, x_1), (l_2, r_2, x_2), dots, (l_m, r_m, x_m)).

    Calculate the number of distinct arrays (a), consisting of (n) integers such that:

    • (0 le a_i < 2^k) for each (1 le i le n);

    • bitwise AND of numbers (a[l_i] & a[l_i + 1] & dots & a[r_i] = x_i) for each (1 le i le m).

    Two arrays (a) and (b) are considered different if there exists such a position (i) that (a_i eq b_i).

    The number can be pretty large so print it modulo (998244353).

    (1 le n le 5 cdot 10^5, 1 le k le 30, 0 le m le 5 cdot 10^5)

    题解

    显然每位独立,分开计算,用乘法原理合并。

    如果(x_i=1),那么毫无疑问区间内所有数都是(1)

    如果(x_i=0),那么区间内至少有一个数为(0)。这个限制跟上一道题一模一样。

    利用前缀和把DP优化到线性。时间复杂度(O(nlog n))

    CO int N=5e5+10;
    struct node {int l,r,x;} a[N];
    int V[N],L[N],S[N];
     
    int solve(int n){
    	fill(S+1,S+n+1,0),S[0]=1;
    	int lim=-1;
    	for(int i=1;i<=n;++i){
    		if(!V[i]){
    			int sum=add(S[i-1],mod-(lim>=0?S[lim]:0));
    			lim=max(lim,L[i]-1);
    			S[i]=add(S[i-1],sum);
    		}
    		else S[i]=S[i-1];
    	}
    	return add(S[n],mod-(lim>=0?S[lim]:0));
    }
     
    int fa[N];
     
    int find(int x){
    	return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    int main(){
    	int n=read<int>(),K=read<int>(),m=read<int>();
    	for(int i=1;i<=m;++i) read(a[i].l),read(a[i].r),read(a[i].x);
    	int ans=1;
    	for(int c=0;c<K;++c){
    		for(int i=1;i<=n;++i) fa[i]=i;
    		fill(V+1,V+n+1,0);
    		for(int i=1;i<=m;++i)if(a[i].x>>c&1)
    			for(int p=find(a[i].r);p>=a[i].l;p=find(p))
    				V[p]=1,fa[p]=p-1;
    		fill(L+1,L+n+1,0);
    		bool flag=0;
    		for(int i=1;i<=m;++i)if(~a[i].x>>c&1){
    			int p=find(a[i].r);
    			if(!p) {flag=1;break;}
    			L[p]=max(L[p],a[i].l);
    		}
    		if(flag) {ans=0;break;}
    		ans=mul(ans,solve(n));
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    堆和栈的区别
    今天开通博客了!
    【转】Perl中的正则表达式
    【转】Windows server 2008远程桌面轻松搞定
    【转】彻底删除0KB顽固文件或文件夹的方法
    【转】Java URL Encoding and Decoding
    【转】一个女留学生在美国的七年
    【转】风雨20年:我所积累的20条编程经验
    【转】深入浅出REST
    【转】Python正则表达式指南
  • 原文地址:https://www.cnblogs.com/autoint/p/12695784.html
Copyright © 2011-2022 走看看