zoukankan      html  css  js  c++  java
  • 模拟赛 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;
    }
    
  • 相关阅读:
    调试导论
    CSP-S2 2020 游记
    【题解】51nod 1327 棋盘游戏
    基础数学专题复习
    ubuntu 下 zsh 插件及安装方式
    ubuntu 下 Deepin-TIM 折腾笔记
    微服务学习笔记
    使用 Portainer 管理 Docker 笔记(含本地和远程)
    博客收藏
    定制unittest测试报告【转】
  • 原文地址:https://www.cnblogs.com/lnzwz/p/12829844.html
Copyright © 2011-2022 走看看