CSPJ简易题解
T1
显然的二进制拆分。
由于闲的没事干所以写了个栈(
采用树状数组那样的 lowbit
写法求出每一个 \(1\)。
代码:
#if 0
长春这天下大雨,武昌这天下大雨。
连续两天下大雨,持续两天下大雨。
东京前天下大雨,龙华前天下大雨。
显然今天下大雨,勿忘今天下大雨。
双人飞天下大雨,泪雨滂沱下大雨。
我也想他下大雨,直接让他下大雨。
德州后天下大雨,虽然昨天下大雨。
六月份天下大雨,后五月天下大雨。
#endif
#include<bits/stdc++.h>
using namespace std;
int read(){
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar()))x=x*10+(ch^'0');
return x;
}
int main(){
freopen("power.in","r",stdin);
freopen("power.out","w",stdout);
int n=read();
if(n&1)puts("-1");
else{
stack<int>tmp;
while(n)tmp.push(n&-n),n&=n-1;
while(!tmp.empty())printf("%d ",tmp.top()),tmp.pop();
}fflush(stdout);
return 0;
}
T2
显然的维护值域计数器。
由于闲着没事干莽了个线段树。
代码:
#if 0
长春这天下大雨,武昌这天下大雨。
连续两天下大雨,持续两天下大雨。
东京前天下大雨,龙华前天下大雨。
显然今天下大雨,勿忘今天下大雨。
双人飞天下大雨,泪雨滂沱下大雨。
我也想他下大雨,直接让他下大雨。
德州后天下大雨,虽然昨天下大雨。
六月份天下大雨,后五月天下大雨。
#endif
#include<bits/stdc++.h>
using namespace std;
int read(){
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar()))x=x*10+(ch^'0');
return x;
}
const int N=609,M=1024;
int zkw[N<<2];
inline void update(int x){
for(++zkw[x+=M];x>>=1;zkw[x]=zkw[x<<1]+zkw[x<<1|1]);
}
inline int query(int num){
register int pos=1;
while(pos<M){
if(zkw[pos<<1]>=num)pos<<=1;
else num-=zkw[pos<<1],pos=pos<<1|1;
}return pos-M;
}
int main(){
freopen("live.in","r",stdin);
freopen("live.out","w",stdout);
register int n=read(),w=read();
for(register int i=1;i<=n;++i){
update(601-read());
printf("%d ",601-query(max(i*w/100,1)));
}fflush(stdout);
return 0;
}
T3
有点小难度。
思路:维护表达式树(<-初赛内容)。
解析字符串建表达式树部分略。
先处理 not
,在节点上打标记,然后先根遍历下放,途中 and
,or
互换,\(0\),\(1\) 也互换。
然后后根遍历求出每个点对应的表达式子树的值。
然后先根遍历,遍历到一个点的时候,如果这个点的父亲和兄弟使得表达式计算到这里时出现了和 \(0\) and
或者和 \(1\) or
就代表这个点被废弃了(无用),打个标记。
然后先根遍历下传标记。
最后改变一个点的值的时候,如果这个点有废弃标记,那肯定没影响。
反之,则一定一路都是和 \(1\) and
或者和 \(0\) or
,自然答案也会改变。
代码:
#if 0
长春这天下大雨,武昌这天下大雨。
连续两天下大雨,持续两天下大雨。
东京前天下大雨,龙华前天下大雨。
显然今天下大雨,勿忘今天下大雨。
双人飞天下大雨,泪雨滂沱下大雨。
我也想他下大雨,直接让他下大雨。
德州后天下大雨,虽然昨天下大雨。
六月份天下大雨,后五月天下大雨。
#endif
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+9;
int fa[N],tot;
int lson[N],rson[N];
bool val[N];
int fst[N];
char op[N];
bool tag[N];
char f[N],*p=f;
bool abded[N];
stack<int>stk;
int read_on_str(){
#define getchar() *(p++)
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar()))x=x*10+(ch^'0');
--p;
return x;
}
void Pr_str(){
gets(f);
while(*p){
while(*p==' ')++p;
if(*p=='x'){
fst[read_on_str()]=++tot;
stk.push(tot);
}else if(*p=='&'||*p=='|'){
op[++tot]=*(p++);
register int u=stk.top();stk.pop();
fa[u]=tot,lson[tot]=u;
u=stk.top();stk.pop();
fa[u]=tot,rson[tot]=u;
stk.push(tot);
}else{
++p;
register int u=stk.top();
tag[u]^=1;
}
}
}
#undef getchar
int read(){
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar()))x=x*10+(ch^'0');
return x;
}
int main(){
freopen("expr.in","r",stdin);
freopen("expr.out","w",stdout);
Pr_str();
register int n=read();
for(register int i=1;i<=n;++i)val[fst[i]]=read();
for(register int i=tot;i;--i)if(tag[i]){
tag[lson[i]]^=1,tag[rson[i]]^=1;
if(op[i]=='|')op[i]='&';
else if(op[i]=='&')op[i]='|';
else val[i]^=1;
}
for(register int i=1;i<=tot;++i){
if(op[i]=='|'){
if(val[lson[i]])abded[rson[i]]=true;
if(val[rson[i]])abded[lson[i]]=true;
val[i]=val[lson[i]]|val[rson[i]];
}
else if(op[i]=='&'){
if(!val[lson[i]])abded[rson[i]]=true;
if(!val[rson[i]])abded[lson[i]]=true;
val[i]=val[lson[i]]&val[rson[i]];
}
}
for(register int i=tot;i;--i)if(abded[i])abded[lson[i]]=abded[rson[i]]=true;
register char ret=val[tot]^'0';
for(register int q=read();q;--q){
putchar(ret^!abded[fst[read()]]),putchar('\n');
}fflush(stdout);
return 0;
}
T4
显然的 dp,状态为当前坐标和上一次从哪里走来。
瞎转移即可,见代码。
#if 0
长春这天下大雨,武昌这天下大雨。
连续两天下大雨,持续两天下大雨。
东京前天下大雨,龙华前天下大雨。
显然今天下大雨,勿忘今天下大雨。
双人飞天下大雨,泪雨滂沱下大雨。
我也想他下大雨,直接让他下大雨。
德州后天下大雨,虽然昨天下大雨。
六月份天下大雨,后五月天下大雨。
#endif
#include<bits/stdc++.h>
using namespace std;
int read(){
register char ch;
register bool f=false;
while(!isdigit(ch=getchar()))if(ch=='-')f=true;
register int x=ch^'0';
while(isdigit(ch=getchar()))x=x*10+(ch^'0');
return f?-x:x;
}
long long dp[3][1009][1009];
//0:从左;1:从下;2:从上;
int val[1009][1009];
inline long long ut_max(long long a,long long b){
return a>b?a:b;
}
inline long long ut_max(long long a,long long b,long long c){
return ut_max(a,ut_max(b,c));
}
int main(){
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
register int n=read(),m=read();
for(register int i=1;i<=n;++i)
for(register int j=1;j<=m;++j)
val[i][j]=read();
dp[0][1][1]=val[1][1];
for(int i=2;i<=n;++i)dp[0][1][i]=-1e12;
for(register int j=1;j<=m;++j){
dp[1][j][n]=dp[2][j][1]=-1e12;
if(j>1)for(register int i=1;i<=n;++i)
dp[0][j][i]=ut_max(dp[0][j-1][i],dp[1][j-1][i],dp[2][j-1][i])+val[i][j];
for(register int i=n-1;i;--i)
dp[1][j][i]=ut_max(dp[1][j][i+1],dp[0][j][i+1])+val[i][j];
for(register int i=2;i<=n;++i)
dp[2][j][i]=ut_max(dp[2][j][i-1],dp[0][j][i-1])+val[i][j];
}
printf("%lld\n",ut_max(dp[0][m][n],dp[2][m][n]));
fflush(stdout);
return 0;
}
Over.