23ICPC沈阳站补题
思路来源
E dp BFS记忆化搜索
羊过河
记录羊和狼的数量状态
注意queue中的操作步数是递增的,每个状态第一次遍历到一定是最小的步数
const int N=105,mod=1e9+7,inf=1e9+10;
int x,y,p,q;
int dp[N][N][2];//[sheep数量][wolf数量][0:本岸到对岸 1:从对岸回来]
struct st{int s,w,dir;
};
//记忆化搜索
void solve(){cin>>x>>y>>p>>q;// memset(dp,0x3f,sizeof dp);// if(y>x+2*q)return cout<<-1<<endl,void(); 可以一些动物在船上 所以该条件不能判断非法dp[x][y][0]=0;//[w][s]只记录0岸边的queue<st>qu;//注意先到的步数最少 qu的dir递增qu.push({x,y,0});int ans=inf;while(qu.size()){auto [s,w,dir]=qu.front();qu.pop();// if(s==0)ans=min(ans,dp[s][w][dir]);在前面的一定步数很少if(s==0)return cout<<dp[s][w][dir]<<endl,void();if(dir==0){//枚举运走多少forr(i,0,min(p,s)){forr(j,0,min(p-i,w)){if(s>i&&w-j>s-i+q)continue;//此岸不会有伤亡if(dp[s-i][w-j][dir^1]==0){//最先到的一定是步数最少的qu.push({s-i,w-j,dir^1});dp[s-i][w-j][dir^1]=dp[s][w][dir]+1;}//TLE:多次更新// if(dp[s-i][w-j][dir^1]>=dp[s][w][dir]+1){// qu.push({s-i,w-j,dir^1});// dp[s-i][w-j][dir^1]=dp[s][w][dir]+1;// }}}}else {//对岸运来多少forr(i,0,min(p,x-s)){forr(j,0,min(p-i,y-w)){if(x-s>i&&y-w-j>x-s-i+q)continue;//对岸没有伤亡// if(dp[s+i][w+j][dir^1]>=dp[s][w][dir]+1){// qu.push({s+i,w+j,dir^1});// dp[s+i][w+j][dir^1]=dp[s][w][dir]+1;// }if(dp[s+i][w+j][dir^1]==0){qu.push({s+i,w+j,dir^1});dp[s+i][w+j][dir^1]=dp[s][w][dir]+1;}}}}}cout<<-1<<endl;
}
J 思维
一开始没理解好“isomorphic(同构)”的意思,不是点的标号对应,而是结构对应
u,v两个值中若有叶子节点,变过去就同构。
每次选非叶子节点,把它变成叶子节点。
int deg[N];
//每次操作都会多一个叶子节点
//注意理解“同构” 不是“相同”
void solve(){int n;cin>>n;forr(i,1,n-1){int u,v;cin>>u>>v;deg[u]++,deg[v]++;}int cnt=0;forr(i,1,n){if(deg[i]>1)cnt++;}if(cnt>0&&(cnt-1)&1)cout<<"Alice"<<endl;else cout<<"Bob"<<endl;
}
K 线段树动态开点
给出变化值,求max rating可能的层数区间,初始max rating是0,正数顺序摆放可以创造贡献
- 最多的层数:正数顺序放在开始,后面掉分无贡献
- 最少的:负数放在开始,让一部分正数去抵消。贪心思想:用较小的正数,抵消的层数多,把较大的正数放在后面。
const int N=1e6+5,mod=1e9+7,inf=1e9+10;
int a[N],id;
//线段树 对sum区间修改单点访问
//和值动态开点 对区间二分 贪心
struct node{int lt,rt;//子节点值int l,r;//维护的数值范围int sum,cnt;//和值 区间数字个数
}tr[N*10];
void pushup(int pos){tr[pos].sum=tr[tr[pos].lt].sum+tr[tr[pos].rt].sum;tr[pos].cnt=tr[tr[pos].lt].cnt+tr[tr[pos].rt].cnt;
}
void add(int &pos,int l,int r,int val,int op){if(!pos){//新节点pos=++id;tr[pos].l=l,tr[pos].r=r;}if(l==r){tr[pos].sum+=val*op;tr[pos].cnt+=op;return;}int mid=(l+r)>>1;if(val<=mid)add(tr[pos].lt,l,mid,val,op);else add(tr[pos].rt,mid+1,r,val,op);pushup(pos);
}
//最少用多少
//输入的sum是先负再正的总值
int query(int pos,int l,int r,int sum){if(sum<=0)return 0;if(l==r){//sum已经除掉>l部分,sum中包含tr[pos].cnt个l值return (sum+l-1)/l;//这里就计算多少个l值能把sum搞到<0}int mid=(l+r)>>1;//算后面正数 抵消前面负数后剩的贡献if(tr[tr[pos].rt].sum>=sum)return query(tr[pos].rt,mid+1,r,sum);else return query(tr[pos].lt,l,mid,sum-tr[tr[pos].rt].sum)+tr[tr[pos].rt].cnt;//让前面小的去抵消负数
}
void solve(){int n,q;cin>>n>>q;int sm=0,rt=0;forr(i,1,n){cin>>a[i];if(a[i]>0)add(rt,1,inf,a[i],1);//把正数记录下来sm+=a[i];}forr(i,1,q){int x,v;cin>>x>>v;if(a[x]>0)add(rt,1,inf,a[x],-1);if(v>0)add(rt,1,inf,v,1);sm+=v-a[x];a[x]=v;cout<<tr[1].cnt-query(1,1,inf,sm)+1<<endl;}
}
M 找规律 进制
需要灵机一动
s→ts\rightarrow ts→t即s⊕s=0→s⊕ts\oplus s=0\rightarrow s\oplus ts⊕s=0→s⊕t
而要经过t点k次,就要0→00\rightarrow 00→0
发现按题意转移,每两位按00→01→11→1000\rightarrow01\rightarrow11\rightarrow1000→01→11→10变化,可以看作四进制
const int N=1e6+2,V=2e4+5,mod=1e9+7,inf=1e9+10;
int p[N+5];int qpos(int x,int p=mod-2){int res=1;for(;p;p>>=1,x=1ll*x*x%mod)if(p&1)res=res*x%mod;return res;
}
void init(){p[0]=1;forr(i,1,N)p[i]=p[i-1]*4%mod;forr(i,1,N)(p[i]+=p[i-1])%mod;
}
void solve(){string s,t;cin>>s>>t;int k;cin>>k;int ls=s.size(),lt=t.size();s=' '+s,t=' '+t;//发现规律 00->01->11->10 四进制//以进制思维去想//0->s^t + 0->0//s^treverse(s.begin()+1,s.end());reverse(t.begin()+1,t.end()); if(ls<=lt){forr(i,ls+1,lt)s+='0';ls=lt;}else {forr(i,lt+1,ls)t+='0';}forr(i,1,ls)s[i]=(s[i]!=t[i])+'0';//0->0//判断合法:后面的00有多少个 k就能循环多少圈 即z/2 +1是初始状态int z=0;forr(i,1,ls){if(s[i]=='1')break;else z++;}if(ls!=z&&z/2+1<k)return cout<<-1<<endl,void();//0->s^tif(ls&1)s+='0';int ans=0;for(int i=1;i<=ls;i+=2){//p是4^0+...+4^pos 就是本位四进制转多少圈回0 //从低到高位去掉1if(s[i]=='0'&&s[i+1]=='1')(ans+=3*p[i/2]%mod)%=mod;//10 要转3圈 00->01->11->10else if(s[i]=='1'&&s[i+1]=='1')(ans+=2*p[i/2]%mod)%=mod;//11 转2圈00->01->11else if(s[i]=='1'&&s[i+1]=='0')(ans+=p[i/2])%=mod;//01 转一圈00->01} // cout<<ans<<endl;(ans+=(qpos(4,k)-4+mod)%mod*qpos(3)%mod)%=mod;cout<<ans<<endl;
}