一开始看洛谷的题解还是有点蒙,仔细想想,发现规律之后代码就好写了。
AC思路
n个数字,一共有n-1个空去填运算符号。那么一共具有3n−1种情况,暴力枚举是不太行的。
数学推导:
既然异或运算的优先级是最高的,那么就可以将所有异或的看成一块,以加减将这些块分割开来。
可以发现的是,加和减是对应的。 对于n-1 个空位中的某一位的某一“块”,只要有加,那么对立面一定有减,使得抵消掉,对最终的贡献为0。但是考虑到第一位之前不可以添加符号,那么和第一位相关联的某一块的贡献的累加就是最终的累加和,注意这里的某一块是异或运算和。
res=sum(异或和i∗2∗3(n−1)−1−(异或符的占用位) )
AC代码
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N = 100010, mod = 1e9+7;
ll a[N],n;
ll pre[N];
ll fast_pow_mod(int a, int b, int p)
{
ll res = 1;
while(b)
{
if(b & 1 == 1)
res = res * a % p;
a = (ll)a*a % p;
b >>= 1;
}
return res;
}
int main()
{
scanf("%lld",&n);
for(int i = 1; i <= n; i ++)
scanf("%lld",&a[i]);
//预处理前缀异或和
for(int i = 1; i <= n; i ++)
pre[i] = pre[i-1] ^ a[i];
ll res = pre[n]; //n
for(int i = 1; i <= n-1; i ++) //1—n-1
res = res % mod + pre[i]*2*fast_pow_mod(3,(n-1)-1-(i-1),mod) % mod;
printf("%lld",(res%mod+mod)%mod);
return 0;
}
暴力30%思路
使用 dfs 暴力搜索,遍历3n−1种运算符的选择情况,核心是如何进行计算某一种确定的情况。因为涉及到计算的优先级次序,所以需要较为复杂的模拟。dfs 通过调用calcu()
函数,来计算并返回一种确定的情况的结果,最后累加在一起。
暴力代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 100010,mod = 1e9+7;
vector<ll> a;
int n;
int sta[N]; //0未选择,1异或,2加,3减
ll res;
ll calcu() //处理一种运算符情况的运算结果
{
vector<ll> mid_num;
vector<int> mid_ops;
mid_num.push_back(a[0]); //以第一个数为运算起点
//处理异或运算
for(int i = 0; i <= n-2; i ++) //遍历所有的运算符
//运算符i是用来处理数字 i 和数字 i+1 的
{
if(sta[i] == 1) //异或运算
{
//先拿出第一个数
ll cur_res = mid_num.back();
mid_num.pop_back();
//和下一个数进行异或运算
cur_res ^= a[i+1]; //和a[i+1]进行运算
mid_num.push_back(cur_res); //再存进去
}
//加减运算先存入,之后处理
else if(sta[i] == 2)
{
mid_ops.push_back(2);
mid_num.push_back(a[i+1]);
}
else
{
mid_ops.push_back(3);
mid_num.push_back(a[i+1]);
}
}
//处理加减运算
ll cur_res = mid_num[0];
for(int i = 0; i < mid_ops.size(); i ++)
{
if(mid_ops[i] == 2) //加法
{
cur_res += mid_num[i+1];
}
else
{
cur_res -= mid_num[i+1];
}
}
return cur_res;
}
void dfs(int u) //n-1个空位,索引范围为0—n-2 u表示要填的坑位
{
if(u == n-1) //所有 n-1 个运算符都已选择
{
ll cur_res = calcu();
res = (res + cur_res) % mod;
return;
}
for(int op = 1; op <= 3; op ++) //三种操作符
{
if(sta[u] == 0)
{
sta[u] = op;
dfs(u+1);
sta[u] = 0;
}
}
}
int main()
{
scanf("%d",&n);
for(int i = 0; i < n; i ++)
{
ll num;
scanf("%lld",&num);
a.push_back(num);
}
dfs(0);
printf("%lld",res);
return 0;
}