专栏文章
题解:P12521 [Aboi Round 1] ATRI
P12521题解参与者 4已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @mip8i4gl
- 此快照首次捕获于
- 2025/12/03 07:53 3 个月前
- 此快照最后确认于
- 2025/12/03 07:53 3 个月前
考虑操作树, 为深度为奇数的数的异或和,归纳可得深度为奇数的点数在模 固定。
转化为:
给定 和大小为 的可重集 。求有多少种 的子集 的异或和,且 。
显然有 的 dp 做法。
设 的(异或空间)线性基大小为 。显然最多 种数可以被凑出。
大胆猜测,当 大于某个阈值 时,直接输出这 种数。
时跑 的 dp。
CPP#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<string>
#include<bitset>
#include<numeric>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1<<16;
const int MAXL=4e4+10;
const int L=4e4;
const int INF=0x3f3f3f3f;
const long long LINF=0x3f3f3f3f3f3f3f3f;
int n,m;
int t[MAXL];
bool dp[3][MAXN],lst[3][MAXN];
namespace basis{
int S=0;
int lb[16];
inline void ins(int x){
for(int i=15;~i;i--)
{
if(x&(1<<i)){
if(!lb[i]){
lb[i]=x;
S|=1<<i;
return ;
}
x^=lb[i];
}
}
}
inline void clr(){
S=0;
memset(lb,0,sizeof(lb));
}
inline void prt(){
basic_string <int> ans;
ans.push_back(0);
for(int s=S;s;s=(s-1)&S)
{
int x=0;
for(int i=0;i<16;i++)
{
if(s&(1<<i)){
x^=lb[i];
}
}
ans.push_back(x);
}
sort(ans.begin(),ans.end());
for(int x:ans)
{
printf("%d ",x);
}
putchar('\n');
}
}
inline void solve(){
scanf("%d",&n);
m=t[n];
if(n>=82){
basis::clr();
while(n--)
{
int x;
scanf("%d",&x);
basis::ins(x);
}
basis::prt();
return ;
}
memset(dp,false,sizeof(dp));
dp[0][0]=true;
while(n--)
{
int x;
scanf("%d",&x);
memcpy(lst,dp,sizeof(dp));
for(int a:{0,1,2})
{
for(int i=0;i<(1<<16);i++)
{
if(lst[a][i]){
dp[(a+1)%3][i^x]=true;
}
}
}
}
for(int i=0;i<(1<<16);i++)
{
if(dp[m][i]){
printf("%d ",i);
}
}
puts("");
}
signed main(){
#ifdef LOCAL
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
atexit([](){fprintf(stderr,"%.3lfs\n",(double)clock()/CLOCKS_PER_SEC);});
#endif
t[1]=1;
t[2]=2;
for(int i=3;i<=L;i++)
{
t[i]=(i+3-t[i-1])%3;
}
int t;
scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}
发现过了。怎么回事呢。
先别急,这不是一篇乱搞题解。
可以证明,这种做法是对的。
相当于证明:
个数一定可以凑出集合 使得 可以是 且 异或和为 。
发现凑出 使得 即可。
结论: 个数一定可以凑出一个集合 使得 且 异或和为 。
证明:
取 个数,称其集合为 。
其中最多 个数属于 的线性基,称为 。
若干个 的异或和可以表示 中所有数。
剩下的 个数称为 。
对于 , 可表示为 个 的异或和。
- ,那么取 和它对应的这 个 即可。
- 否则 。
根据线性基结论, 个数的线性基一定满,一定可以提取一个子集异或和为 。
必有 。
- 若 ,取这 个 即可。
- 否则将 替换成其对应的 个 ,此时数量为 。
所以 有下界 。
时间复杂度 。
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...