题意: 对一个长度为n的数组,求长度小于m的子数组的最大异或和。
暴力双指针做法复杂度n2会超时。
做法:对于区间和,先预处理出一个前缀异或和,所以题目转化为对数组找两个距离小于m的数使他们的异或值最大,就变成了加了限制条件的最大异或对这道题了。用01trie树做,对于限制条件,可以定义一个cnt数组表示树中每个节点被走过的次数,不在m的区间内的数,他们在树中走过的点cnt全部-1,复杂度 nlogn。
关键点:找区间转化为找点、01trie树找最大异或对、用cnt数组处理限制条件。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n,m,s[N],son[N * 31][2],idx,cnt[N * 31];//注意空间开的大小
void add(int x,int v)//加入trie
{
int p = 0;
for(int i = 30; i >= 0; i -- )
{
int u = x >> i & 1;
if(!son[p][u])
son[p][u] = ++ idx;
p = son[p][u];
cnt[p] += v;
}
}
int query(int x)//得到x与trie中存在数的异或最大值
{
int p = 0,ans = 0;
for(int i = 30; i >= 0; i -- )
{
int u = x >> i & 1;
if(cnt[son[p][u ^ 1]])//如果能走
{
p = son[p][u ^ 1];
ans |= (1 << i);
}
else
p = son[p][u];
}
return ans;
}
int main()
{
int ans = 0;
cin>>n>>m;
for(int i = 1; i <= n; i ++ )//预处理前缀异或和
{
cin>>s[i];
s[i] ^= s[i - 1];
}
add(s[0],1);//别忘了把s[0]加入trie
for(int i = 1; i <= n; i ++ )
{
if(i > m)
add(s[i - m - 1],-1);//删除不在区间内的
ans = max(ans,query(s[i]));
add(s[i],1);
}
cout<<ans;
return 0;
}
水题,直接上代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
ll n,a[N],s[N],v[N],s1[N],k;
int main()
{
ll maxx = 0;
cin>>n>>k;
for(int i = 1; i <= n; i ++ )
cin>>a[i];
for(int i = 1; i <= n; i ++ )
cin>>v[i];
for(int i = 1; i <= n; i ++ )
{
if(v[i])
s[i] = s[i - 1] + a[i];
else
s[i] = s[i - 1];
s1[i] = a[i] + s1[i - 1];
}
for(int i = 1; i + k - 1 <= n; i ++ )
{
ll x = s[n] - (s[i + k - 1] - s[i - 1]) + (s1[i + k - 1] - s1[i - 1]);
maxx = max(maxx,x);
}
cout<<maxx;
return 0;
}
dp,用 dp[i][j] 表示 i 个数里删j个数且第 i 个不删的最大收益.
状态计算:从倒数第二个开始,可以为0,1,2…i - 1,当倒数第二个为 k 时,表示 k - i 中的数都被删去(共i - k - 1 个),1 - k 中的数怎么删无所谓,所以可以得到 dp[i][j] = max(dp[i][j],dp[k][j - (i - k - 1)] + g[a[k]][a[i]]),状态的递推感觉有点像区间dp的那道石子合并.
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 210;
int a[N],g[N][N],n,s,m,dp[N][N];//表示i个数里删j个数且第i个不删的最大收益
int main()
{
cin>>n>>s>>m;
for(int i = 1; i <= m; i ++ )
cin>>a[i];
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ )
cin>>g[i][j];
for(int i = 1; i <= m; i ++ )
for(int j = 0; j <= s; j ++ )
for(int k = 0; k <= i - 1; k ++ )//k表示删完之后第i个数上一个的下标
if(i - k - 1 <= j)
dp[i][j] = max(dp[i][j],dp[k][j - (i - k - 1)] + g[a[k]][a[i]]);
cout<<dp[m][s];
return 0;
}
普通的dfs,代码:
#include<bits/stdc++.h>
using namespace std;
set<int>s;
int n,m,k;
int p[10][10];
int dx[] = {0,1,-1,0};
int dy[] = {1,0,0,-1};
void dfs(int x,int y,int num,int K)
{
if(K == k + 1)
{
s.insert(num);
return ;
}
for(int i = 0; i < 4; i ++ )
{
int nx = x + dx[i];
int ny = y + dy[i];
if(nx > 0 && nx <= n && ny > 0 && ny <= m)
{
dfs(nx,ny,num * 10 + p[nx][ny],K + 1);
}
}
}
int main()
{
cin>>n>>m>>k;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= m; j ++ )
cin>>p[i][j];
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= m; j ++ )
dfs(i,j,p[i][j],1);
cout<<s.size();
return 0;
}
数据变大了,不能用最长公共子序列的dp板子,想着靠a中没有重复元素优化(还是太菜了想不出来)
y总思路:新开一个数组c,由于a中元素不重复,将b中与a相同的元素的下标存入c,不存在则置-1,所以只需要c中是上升序列就一定存在b和a是公共序列,问题转化为求c的长上升子序列问题,复杂度降为nlogn。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1000010;
int q[N],a[N],b[N],c[N],id[N],n;
int main()
{
cin>>n;
memset(id,-1,sizeof(id));//初始化不能忘
for(int i = 0; i < n; i ++ )
{
cin>>a[i];
id[a[i]] = i;//相当于一个map,存的下标,用来求c
}
for(int i = 0; i < n; i ++ )
{
cin>>b[i];
if(id[b[i]] != -1)
c[i] = id[b[i]];
else
c[i] = -1;
}
q[0] = -1;//先放入一个数,方便比较
int hh = 0;
for(int i = 0; i < n; i ++ )//最长上升子序列
{
if(c[i] != -1)
{
if(c[i] > q[hh])
q[++ hh] = c[i];
else
{
int t = lower_bound(q,q + hh + 1,c[i]) - q;
q[t] = c[i];
}
}
}
cout<<hh;
return 0;
}
最古老的模拟题,但其实挺麻烦的,想到自己大一蓝桥杯就有一道这样的填空调一个多小时都调不出来,当时郁闷了好久哈哈,现在不用调试就ac了
代码:
#include<bits/stdc++.h>
using namespace std;
int d,y;
string m;
string s[12] = {"January","February","March","April","May","June","July","August","September","October","November","December"};
int c[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
string w[7] = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
bool is(int x)
{
if(x % 400 == 0)
return true;
if((x % 4) == 0 && x % 100)
return true;
return false;
}
int main()
{
while(cin>>d>>m>>y)
{
int res = 0,day = 0;
for(int i = 1; i <= y - 1; i ++ )
if(is(i))
res ++ ;
day += ((y - 1) * 365 + res);
int month = 0;
for(int i = 0; i < 12; i ++ )
if(m == s[i])
month = i;
for(int i = 0; i <= month - 1; i ++ )
{
if(i == 1)
{
if(is(y))
day += 29;
else
day += 28;
continue;
}
day += c[i];
}
day += d;
day %= 7;
cout<<w[day]<<endl;
}
return 0;
}
0的阶乘是1!!
#include<bits/stdc++.h>
using namespace std;
int n,a[10];
int fun(int x)
{
int res = 1;
while(x)
{
res *= x;
x --;
}
return res;
}
int main()
{
for(int i = 1; i <= 9; i ++ )
a[i] = fun(i);
a[0] = 1;
while(cin>>n && n >= 0)
{
if(n == 0)
{
cout<<"NO"<<endl;
continue;
}
bool flag = false;
for(int i = 0; i < (1 << 10); i ++ )
{
int res = 0;
bitset<32>p(i);
for(int j = 0; j < 10; j ++ )
if(p[j])
res += a[j];
if(res == n)
{
cout<<"YES"<<endl;
flag = true;
break;
}
}
if(!flag)
cout<<"NO"<<endl;
}
return 0;
}