• 洛谷 U140360 购物清单


    洛谷 U140360 购物清单

    洛谷传送门

    题目背景

    光阴似箭,日月如梭。不知不觉间,时间已经快进到SeawaySeawa**y带着一家老婆小孩过上了幸福快乐的生活......

    题目描述

    当然,虽然生活的大体格调是幸福而快乐的,但是SeawaySeawa**y依然躲不过生活中的柴米油盐酱醋茶等琐碎小事。其中,最让他为难的便是半个月一次的采购了......

    每次采购,SeawaySeawa**y要列出一份购物清单,并按清单顺序购入下半个月所需要的nn件物品。超市一共有2k2*k*种物品。为了方便,Seaway*S**e**a**w**a**y*把这些物品从0-2k-10−2k−1编号。现在问题在于,SeawaySeawa**y每次采购都要满足老婆孩子的mm条要求,这些要求形如(l,r,x)(l,r,x)。其意义是:假设SeawaySeawa**y的购物清单是一个数列aa,那么对于第ii条要求(l_i,r_i,x_i)(l**i,r**i,x**i),SeawaySeawa**y的购物清单必须满足:a[l_i] &a[l_i+1]&cdots&a[r_i]=x_ia[l**i]&a[l**i+1]&⋯&a[r**i]=x**i。其中&&是按位与运算。SeawaySeawa**y的购物清单合法,当且仅当它能同时满足老婆孩子的mm条要求。

    SeawaySeawa**y在经过严密地思考后发现,这样的清单不唯一。所以他想请你帮他统计:对于这mm条要求,有多少种清单合法。我们定义两个清单a,ba,b不同,当且仅当存在至少一个位置ii使得a_i eq b_ia**i�=b**i。答案对998,244,353998,244,353取模。

    输入格式

    从文件list.inlis**t.i**n中读入数据。

    第一行三个整数n,m,kn,m,k,意义如题目描述所示。

    接下来的mm行,每行三个整数l_i,r_i,x_il**i,r**i,x**i,描述一个限制(l,r,x)(l,r,x)。

    输出格式

    输出到文件list.outlis**t.out中。

    输出一行一个整数ansans,表示满足条件的清单种数按要求取模后的结果。


    命题背景:

    这题实在是比较狗。

    u1s1,一开始拿到的时候只推出来了性质,至于实现想破脑袋都没想明白。还是太菜了。

    本来没想拿这道题,但是一看好像和动物园那道题挺像。位运算+DP都是热门考点,所以就拿来考了。

    感觉像黑题。但是可能也只是因为我菜吧。不好意思让洛谷改评分了。所以只在自己的题里改了评分。


    题解:

    对于这种题目,一般都是从位运算按位独立这里入手。这题也不例外。

    既然位运算相互独立,且本题只有与运算,那么很容易得出这样的一个性质:对于某个约束区间([l,r])的约束值(x),对(x)二进制拆分,(x)的某位如果为1,那么这个区间的数的对应位全部为1。反之如果为0,那么这个区间的数的对应位至少有一个为0.

    推到此处狂喜,然后觉得可以用排列组合来做,或者是个容斥什么的。但是这是不现实的,因为区间的并实在太难处理了。

    但是想到排列组合却能给我们一个启发。那就是计数原理的乘法原理。既然这些位都是互相独立的,那么每位的合法方案的方案数乘到一起就是答案。

    每位的合法方案数......既然排列组合容斥啥的都没戏,那就只能考虑DP,毕竟对于计数类问题我们也并没有什么其他的方法。这个不行就试那个。

    (dp[i])表示处理到前i个数,且第(i)个数的对应位为0的方案数。不需要再开一维来存第几位,每次做的时候清空即可。

    那么很显然,如果某个约束条件使得一个区间内的数字的对应位为1,那么这段区间的dp值应该都为0.

    这个0可以用多种方法维护,我选择的是差分。

    如果某个约束条件使得一个区间内的数字的对应位至少有一个为0,这种情况该怎么办呢?

    分类讨论:首先如果某个区间的右端点比当前枚举到的点大,那么这个条件已经被满足,不用考虑。

    如果某个区间([l,r])的右端点比当前枚举到的点(i)小,那么这个条件要被满足,一定会在这里填一个0,所以就可以转移:

    [dp[i]=sum_{j=l}^{i-1}dp[j] ]

    为什么要到(i-1)而不是到(r)呢?因为我们统计的(dp[i])已经被叫做合法方案,所以在这个区间的都合法,也就都要统计进来。

    那么我们敏锐地发现,这样统计会导致很多区间被重复算进去。那么我们为了不重复统计,就采用一个(lmx[i])数组,表示在(i)左边最大的(l)值。这样的话每次转移只会从最大的开始累加,而前面的已经在前面的转移被累加过了。这样就完成了这道题。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=5e5+5;
    const int mod=998244353;
    int n,k,m;
    int l[maxn],r[maxn],x[maxn];
    int lmx[maxn],dp[maxn],cf[maxn];
    int calc(int a)
    {
    	memset(lmx,0,sizeof(lmx));
    	memset(cf,0,sizeof(cf));
    	memset(dp,0,sizeof(dp));
    	for(int i=1;i<=m;i++)
    	{
    		if(x[i]>>a&1)
    			cf[l[i]]++,cf[r[i]+1]--;
    		else
    			lmx[r[i]]=max(lmx[r[i]],l[i]);
    	}
    	for(int i=1;i<=n+1;i++)
    	{
    		lmx[i]=max(lmx[i],lmx[i-1]);
    		cf[i]+=cf[i-1];
    	}
    	int sum=1,j=0;
    	dp[0]=1;
    	for(int i=1;i<=n+1;i++)
    	{
    		if(cf[i])
    		{
    			dp[i]=0;
    			continue;
    		}
    		while(j<lmx[i-1])
    		{
    			sum=(sum-dp[j]+mod)%mod;
    			j++;
    		}
    		dp[i]=sum;
    		sum=(sum+dp[i])%mod;
    	}
    	return dp[n+1];
    }
    int main()
    {
    	scanf("%d%d%d",&n,&k,&m);
    	for(int i=1;i<=m;i++)
    		scanf("%d%d%d",&l[i],&r[i],&x[i]);
    	int ans=1;
    	for(int i=0;i<k;i++)
    		ans=1ll*ans*calc(i)%mod;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    动态加载JS脚本【转】
    定义并且立即执行JS匿名函数拾遗
    javascript操作ASCII码与字符对转
    win7的mklink命令
    [Yii Framework] How to get the current static page name?
    [Ubuntu] 利用Ubuntu光盘破解win7用户登录 Crark the win7 user via Ubuntu live CD
    [Ubuntu] reload the .bashrc file without logout nor restart.
    [Ubuntu] the permissions of lampp mysql and phpmyadmin
    [Zend PHP5 Cerification] Some note when studying
    [eZ publish] How to modify the $view_parameters valus in the template.
  • 原文地址:https://www.cnblogs.com/fusiwei/p/14026094.html
Copyright © 2020-2023  润新知