• 模拟赛 circle 题解


    题意:有N个数,问有多少个x,((xleq T)),满足这N个数分别+x后,异或和为S。每个数小于(2^M)
    数位DP。
    由于是加法,需要记录进位,因此从低位到高位DP。
    只要记录下有几个进位,就可以根据这N的数的大小知道究竟是哪几个进位了。
    (dp(i,j,0/1))表示考虑到第i位,有j个进位,与T的大小关系为0/1的方案数。
    可以提前预处理出转移,即(g(i,j,0/1))表示考虑到第i位,有j个进位,当前位使用(0/1)造成的进位数。
    时间复杂度(O(NMlogN))(有排序),可以优化至(O(NM))
    代码(未经优化):

    #include <stdio.h>
    #include <stdlib.h>
    #define ll long long
    struct SPx
    {
    	ll z;int i;
    };
    SPx px[52][100010];
    ll sz[100010],dp[52][100010][2];
    int sl[52][100010][2],tm[100010],ss[52];
    int sgn(ll x)
    {
    	if(x>0)
    		return 1;
    	else if(x<0)
    		return -1;
    	return 0;
    }
    int cmp(const void*a,const void*b)
    {
    	return sgn(((SPx*)b)->z-((SPx*)a)->z);
    }
    ll solve(int m,int n,ll S,ll T)
    {
    	if(T==0)return 0;
    	T-=1;
    	for(int i=m;i>=0;i--)
    	{
    		int b=bool(S&(1ll<<i)),bt=bool(T&(1ll<<i));
    		for(int j=0;j<=n;j++)
    		{
    			if(i==m)
    			{
    				dp[i][j][0]=1;
    				continue;
    			}
    			if((ss[i]+j)%2!=b)
    				dp[i][j][0]=dp[i][j][1]=0;
    			else
    			{
    				if(bt==0)
    				{
    					dp[i][j][0]=dp[i+1][sl[i][j][0]][0]+dp[i+1][sl[i][j][1]][1];
    					dp[i][j][1]=dp[i+1][sl[i][j][0]][1]+dp[i+1][sl[i][j][1]][1];
    				}
    				else
    				{
    					dp[i][j][0]=dp[i+1][sl[i][j][0]][0]+dp[i+1][sl[i][j][1]][0];
    					dp[i][j][1]=dp[i+1][sl[i][j][0]][0]+dp[i+1][sl[i][j][1]][1];
    				}
    			}
    		}
    	}
    	return dp[0][0][0];
    }
    ll work(int m,int n,ll S,ll T)
    {
    	ll d=(1ll<<m);
    	return (T/d)*solve(m,n,S,d)+solve(m,n,S,T%d);
    }
    int main()
    {
    	freopen("circle.in","r",stdin);
    	freopen("circle.out","w",stdout);
    	int n,m;ll S,T;
    	scanf("%d%d%lld%lld",&n,&m,&S,&T);
    	for(int i=0;i<n;i++)
    	{
    		ll a;
    		scanf("%lld",&a);
    		sz[i]=a=(a+1)%(1ll<<m);
    		for(int j=0;j<m;j++)
    		{
    			if(a&(1ll<<j))
    				ss[j]=(ss[j]+1)%2;
    			px[j][i].i=i;
    			px[j][i].z=a%(1ll<<(j+1));
    		}
    	}
    	for(int i=0;i<m;i++)
    		qsort(px[i],n,sizeof(SPx),cmp);
    	for(int i=1;i<m;i++)
    	{
    		int s0=0;
    		for(int j=n-1;j>=0;j--)
    			tm[j]=tm[j+1]+bool(sz[px[i-1][j].i]&(1ll<<i));
    		for(int j=0;j<=n;j++)
    		{
    			if(j>0)
    				s0+=bool(sz[px[i-1][j-1].i]&(1ll<<i));
    			sl[i][j][0]=s0;sl[i][j][1]=tm[j]+j;
    		}
    	}
    	sl[0][0][0]=0;
    	for(int i=0;i<n;i++)
    		sl[0][0][1]+=(sz[i]%2);
    	printf("%lld",work(m,n,S,T));
    	return 0;
    }
    
  • 相关阅读:
    jQery总结01
    抽象类和接口精华
    JS基础之开篇
    HTML常见元素集锦
    bzoj3626 [LNOI2014]LCA
    bzoj3223 Tyvj 1729 文艺平衡树
    bzoj3196 Tyvj 1730 二逼平衡树
    bzoj3295 [Cqoi2011]动态逆序对
    bzoj3514 Codechef MARCH14 GERALD07加强版
    bzoj3932 [CQOI2015]任务查询系统
  • 原文地址:https://www.cnblogs.com/lnzwz/p/12829844.html
Copyright © 2020-2023  润新知