今天打了这个比赛,水题挺多~(体验很好(太菜了))
传送门:https://www.jisuanke.com/contest/1557?view=challenges
~A. Hard to prepare
组合数学+递推(通过率: 76.7 %,通过人数: 507)
思路:考虑各个位置有几种选法,对于n,k来说,位置1有2^k种选法,接下来的每一个位置和前一个位置不能完全不同[$1]
,所以有2^k-1种选法,对于位置n,它既要顾及位置n-1的又要顾及位置1,所以就只有2^k-2种选法
但是如果位置n-1和位置1一样,那么位置n-1会多出来一种选法,此时位置n-1和n就是固定的了,前n-2个位置的选法个数变成一个子问题
需要注意的是如果n=1,答案就是2^k,n=2,答案就是2^k*(2^k-1)
$1:(因为完全不同的个数有1个,对于5:101b来说完全不同的只有2:010b)
// https://nanti.jisuanke.com/t/31453
#include<stdio.h>
typedef long long ll;
const int mod=1e9+7;
ll pow(ll x,ll y){
ll ret=1;
for(;y;y/=2,x=x*x%mod)
if(y&1)ret=ret*x%mod;
return ret;
}
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
int t,n,k;scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
ll ans,_2k=pow(2,k);
ans=_2k*(n%2?1:_2k-1)%mod;
for(int i=4-n%2;i<=n;i+=2)
ans+=_2k*(_2k-2)%mod*pow(_2k-1,i-2)%mod;
printf("%lld\n",ans%mod);
}
return 0;
}
~B. BE, GE or NE
博弈规则+记忆化爆搜(通过率: 66.92 %,通过人数: 356)
思路:像数位dp一样dfs搜索,用博弈规则来转移
// https://nanti.jisuanke.com/t/31454
#include<stdio.h>
#include<string.h>
typedef long long ll;
#define only(i,ending) (i==ending||i==2)
#define have(i,ending) (i==ending)
const int maxn=1005,good=1,normal=0,bad=-1;
struct node{int a,b,c;
inline node(int a=0,int b=0,int c=0):a(a),b(b),c(c){}
}arr[maxn];
int rounds,initscore,goodend,badend;
int ending[maxn][201];
int dfs(int round,int score){
if(score>+100)score=+100;
if(score<-100)score=-100;
if(round>rounds)
return (score>=goodend)-(score<=badend);
if(ending[round][score]!=0x3f3f3f3f)
return ending[round][score];
int res=0,a=2,b=2,c=2;
if(arr[round].a)
a=dfs(round+1,score+arr[round].a);
if(arr[round].b)
b=dfs(round+1,score-arr[round].b);
if(arr[round].c)
c=dfs(round+1,score*-1);
if(round&1==1)//want good ending
if(have(a,good)+have(b,good)+have(c,good))
return ending[round][score]=good;
else if(only(a,bad)*only(b,bad)*only(c,bad))
return ending[round][score]=bad;
else
return ending[round][score]=normal;
else
if(have(a,bad)+have(b,bad)+have(c,bad))
return ending[round][score]=bad;
else if(only(a,good)*only(b,good)*only(c,good))
return ending[round][score]=good;
else
return ending[round][score]=normal;
}
char ans[3][7]={"Bad","Normal","Good"};
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
while(~scanf("%d%d%d%d",&rounds,&initscore,&goodend,&badend)){
memset(ending,0x3f,sizeof ending);
for(int i=1;i<=rounds;i++)
scanf("%d%d%d",&arr[i].a,&arr[i].b,&arr[i].c);
printf("%s Ending\n",ans[dfs(1,initscore)+1]);
}
return 0;
}
F. Features Track
签到模拟(通过率: 88.66 %,通过人数: 1087)
思路:用滚动map维护上一帧出现的点,暴力更新答案,不过每一次用指针new一个O(1)而不是O(n)的clear(不过没什么卵用)
// https://nanti.jisuanke.com/t/31458
#include<stdio.h>
#include<map>
#define newmap m[i&1]
#define lastmap m[1-i%2]
struct Node{
int x,y;
Node(int xx=0,int yy=0){
xx=x;
yy=y;
}
bool operator<(const Node&other)const{
return x==other.x?y<other.y:x<other.x;
}
bool operator>(const Node&other)const{
return !(*this<other||*this==other);
}
bool operator==(const Node&other)const{
return x==other.x&&y==other.y;
}
}node;
std::map<Node,int>*m[2];
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
int t;scanf("%d",&t);
while(t--){
m[1]=new std::map<Node,int>();
int n,max=0;scanf("%d",&n);
for(int i=0;i<n;i++){
newmap=new std::map<Node,int>();
int k;scanf("%d",&k);
while(k--){
scanf("%d%d",&node.x,&node.y);
newmap->operator[](node)=1;
}
auto it=newmap->begin(),jt=lastmap->begin();
while(it!=newmap->end()&&jt!=lastmap->end()){
if(jt->first<it->first)
jt++;
else if(jt->first>it->first)
it++;
else{
it->second+=jt->second;
if(it->second>max)
max=it->second;
it++,jt++;
}
}
}
if(max==1)
puts("0");
else
printf("%d\n",max);
}
return 0;
}
G. Trace
逆向输入+线段树(通过率: 72.86 %,通过人数: 663)
思路:反向加每一个矩形(避免后效性)
用一横一竖两颗线段树维护区间最大值
每次查询的答案就是是x[i]+y[i]-h.query(xp)-v.query(yp)
h=horizontal 水平的,v=vertical 垂直的
// https://nanti.jisuanke.com/t/31459
#include<stdio.h>
#include<string.h>
#include<algorithm>
const int maxn=50005;
typedef int Array[(1<<17)+2];
int max(int x,int y){return x>y?x:y;}
#define upd(pos,lazy) arr[pos]=max(lazy,arr[pos]),lz[pos]=max(lazy,lz[pos])
struct segtree{
Array arr,lz;
int M,ss[30],top,ans,L,R;
void init(int n){
memset(arr,0,sizeof arr);
memset(lz,0,sizeof lz);
M=1;while(M-2<n)M*=2;
}
bool lzdown(int u){
if(u>M)u/=2;
for(top=0;u;u/=2)ss[top++]=u;
while(top--)
if(lz[u=ss[top]])
upd(u*2,lz[u]),upd(u*2+1,lz[u]),lz[u]=0;
return true;
}
void update(int l,int r,int val){
for(L=R=0,l+=M-1,r+=M+1;l^r^1;l/=2,r/=2){
if(~l&1&&(L||lzdown(L=l^1)))upd(l^1,val);
if( r&1&&(R||lzdown(R=r^1)))upd(r^1,val);
}
for(L/=2;L;L/=2)arr[L]=max(arr[L*2],arr[L*2+1]);
for(R/=2;R;R/=2)arr[R]=max(arr[R*2],arr[R*2+1]);
}
int query(int x){
lzdown(x+=M);
return arr[x];
}
}v,h;
typedef int array[maxn];
array x,sortedx,y,sortedy;
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
for(int n;~scanf("%d",&n);){
for(int i=0;i<n;i++)
scanf("%d%d",x+i,y+i);
memcpy(sortedx,x,n*4);
memcpy(sortedy,y,n*4);
std::sort(sortedx,sortedx+n);
std::sort(sortedy,sortedy+n);
long long ans=0;
v.init(n+1);h.init(n+1);
for(int i=n-1;~i;i--){
int xp=std::lower_bound(sortedx,sortedx+n,x[i])-sortedx+1;
int yp=std::lower_bound(sortedy,sortedy+n,y[i])-sortedy+1;
ans+=x[i]+y[i]-h.query(xp)-v.query(yp);
h.update(1,xp,y[i]);
v.update(1,yp,x[i]);
}
printf("%lld\n",ans);
}
return 0;
}
H. Ryuji doesn’t want to study
简单线段树(通过率: 75.87 %,通过人数: 1025)
思路:两颗线段树,一棵维护(n+1-i)*a[i],另一颗维护a[i]的区间和,单点更新区间求和
注:下面的代码是zkw线段树的
// https://nanti.jisuanke.com/t/31460
#include<stdio.h>
#include<string.h>
typedef long long ll;
const int maxn=100005;
ll arr[(1<<18)+2],iarr[(1<<18)+2],M;
void update(ll*a,int x,ll val){
for(a[x+=M]=val,x/=2;x;x/=2)
a[x]=a[2*x]+a[2*x+1];
}
ll query(ll*a,int l,int r){
ll ans=0;
for(l+=M-1,r+=M+1;l^r^1;l/=2,r/=2){
if(~l&1)ans+=a[l^1];
if( r&1)ans+=a[r^1];
}
return ans;
}
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
for(int n,q;~scanf("%d%d",&n,&q);){
M=1;while(M-2<n)M*=2;
for(int i=M+1;i<=M+n;i++)
scanf("%lld",arr+i);
for(int i=M+1;i<=M+n;i++)
iarr[i]=arr[i]*(M+n+1-i);
for(int i=M;i;i--)
arr[i]=arr[i*2]+arr[i*2+1],
iarr[i]=iarr[i*2]+iarr[i*2+1];
for(int op,l;q--;){
ll r;
scanf("%d%d%lld",&op,&l,&r);
if(op==1){
ll ret1=query(arr,l,r);
ll ret2=query(iarr,l,r);
printf("%lld\n",ret2-ret1*(n-r));
}else{
update(arr,l,r);
update(iarr,l,(n+1-l)*r);
}
}
}
return 0;
}
I. Characters with Hash
签到模拟(通过率: 92.93 %,通过人数: 1485)
思路:就按照题目说的做:把所有字母变成两位的数字,然后去掉前导零,最后输出这个数字串长度
注意1 a a的情况,答案是1
// https://nanti.jisuanke.com/t/31461
#include<stdio.h>
char s[1000005];
int abs(int x){return x<0?-x:x;}
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
int t;scanf("%d",&t);
while(t--){
int n;char c,*p;
scanf("%d %c%*c",&n,&c);
gets(s);
int ans=0;
for(p=s;*p;p++){
if(*p!=c){
ans+=1+(abs(*p++-c)>=10);
break;
}
}
ans+=2*(s-p+n);
if(ans==0&&n)
ans++;
printf("%d\n",ans);
}
return 0;
}
~J. Maze Designer
最小生成树+LCA+倍增(通过率: 78.55 %,通过人数: 227)
思路:在给定的图中找到最大生成树(和最小生成树同理),然后在这棵树上对于每一个询问输出一个树上距离,可以用LCA+倍增在线回答
// https://nanti.jisuanke.com/t/31462
#include<stdio.h>
#include<string.h>
#include<algorithm>
const int maxn=250005;
#define nowcoord i*n+j+1
#define rightcoord i*n+j+2
#define downcoord i*n+j+n+1
int prev[maxn];
int n,m,q,w;char op[2];
void init(){for(int i=0;i<=n*m;i++)prev[i]=i;}
int find(int x){return x==prev[x]?x:prev[x]=find(prev[x]);}
void join(int x,int y){prev[find(x)]=prev[find(y)];}
bool same(int x,int y){return find(x)==find(y);}
struct setedge{
int u,v,w;
}e[maxn*2];
struct edge{
int dest,dist;
struct edge*next;
}ee[maxn*2],*head[maxn];
int cnt,knt;
void addsetedge(int u,int v,int w){
e[cnt].u=u;e[cnt].v=v;e[cnt++].w=w;
}
void addedge(setedge&x){
ee[knt].dest=x.v;
ee[knt].dist=x.w;
ee[knt].next=head[x.u];
head[x.u]=ee+knt++;
ee[knt].dest=x.u;
ee[knt].dist=x.w;
ee[knt].next=head[x.v];
head[x.v]=ee+knt++;
}
int pre[maxn][20],deep[maxn],dist[maxn];
void dfs(int u,int f,int w){
pre[u][0]=f;
deep[u]=deep[f]+1;
dist[u]=dist[f]+w;
for(int i=0;pre[u][i];i++)
pre[u][i+1]=pre[pre[u][i]][i];
for(edge*i=head[u];i;i=i->next)
if(i->dest!=f)
dfs(i->dest,u,1);
}
int lca(int u,int v){
if(deep[u]<deep[v])u^=v^=u^=v;
int delta=deep[u]-deep[v];
for(int i=0;delta;i++,delta/=2)
if(delta&1)
u=pre[u][i];
if(u==v)
return u;
for(int i=19;~i;i--)
if(pre[u][i]^pre[v][i])
u=pre[u][i],v=pre[v][i];
return pre[u][0];
}
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
while(~scanf("%d%d",&n,&m)){
memset(head,knt=cnt=0,sizeof head);
init();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%s%d",op,&w);
if(op[0]!='X')
addsetedge(nowcoord,downcoord,w);
scanf("%s%d",op,&w);
if(op[0]!='X')
addsetedge(nowcoord,rightcoord,w);
}
}
std::sort(e,e+cnt,[](const setedge&a,const setedge&b)->bool{
return a.w>b.w;
});
int c=n*m-1;
for(int i=0;i<cnt&&c;i++)
if(!same(e[i].u,e[i].v)){
addedge(e[i]);
join(e[i].u,e[i].v);
c--;
}
dfs(1,0,0);
scanf("%d",&q);
while(q--){
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
a=a*n+b-n;
c=c*n+d-n;
printf("%d\n",dist[a]+dist[c]-2*dist[lca(a,c)]);
}
}
return 0;
}
打~的题是补的题,嘿嘿嘿