模拟赛 circle 题解


题意:有N个数,问有多少个x,\((x\leq 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 
#include 
#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<=0;j--)
			tm[j]=tm[j+1]+bool(sz[px[i-1][j].i]&(1ll<0)
				s0+=bool(sz[px[i-1][j-1].i]&(1ll<