Dragon slayer
1)开二倍点的解法
需要些优化的搜索
优化1:(学习自正解)
可以在枚举所有状态时,将包含当前状态的所有状态更新
for(int j=0;j<k;j++){
st[i|(1<<j)]=st[i];//优化1
}
优化2:(同样学习自正解)
在对当前状态进行搜索之前,将未被消除的墙点找出来,而不是一开始把墙建出来再在状态中特判
for(int i=0;i<k;i++){
if((f&(1<<i))==0){//当前状态不能消除的墙
for(int j=p[i].st.x;j<=p[i].ed.x;j++){
for(int z=p[i].st.y;z<=p[i].ed.y;z++){
g[j][z]+=1<<i;
}
}
}
}
const int N=31,M=(1<<15)+10;
int n,m,k;
int sx,sy,ex,ey;
int g[N][N];
bool vis[N][N],st[M];
struct P{
PII st,ed;
}p[N];
PII q[N*N];
int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
inline bool bfs(int f){
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
vis[i][j]=0;
g[i][j]=0;
}
}
for(int i=0;i<k;i++){
if((f&(1<<i))==0){//当前状态不能消除的墙
for(int j=p[i].st.x;j<=p[i].ed.x;j++){
for(int z=p[i].st.y;z<=p[i].ed.y;z++){
g[j][z]+=1<<i;
}
}
}
}
int tt=-1,hh=0;
q[++tt]={sx,sy};vis[sx][sy]=1;
while(hh<=tt){
int x=q[hh].x,y=q[hh++].y;
if(x==ex&&y==ey) return true;
for(int i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a<0||b<0||a>n||b>m||vis[a][b]) continue;
if(g[a][b]) continue;
vis[a][b]=1;
q[++tt]={a,b};
}
}
return false;
}
inline void solve(){
cin>>n>>m>>k>>sx>>sy>>ex>>ey;
n*=2,m*=2;
sx=sx*2+1,sy=sy*2+1,ex=ex*2+1,ey=ey*2+1;
for(int i=0;i<k;i++){
int x1,x2,y1,y2;
cin>>x1>>y1>>x2>>y2;
p[i].st.x=min(x1,x2)*2,p[i].st.y=min(y1,y2)*2;
p[i].ed.x=max(x1,x2)*2,p[i].ed.y=max(y1,y2)*2;
}
for(int i=0;i<(1<<k);i++){
st[i]=0;
}
int ans=k;
for(int i=0;i<(1<<k);i++){
if(st[i]) continue;
st[i]=bfs(i);
if(st[i]){
int cnt=0,t=i;
for(int j=0;j<k;j++){
cnt+=t&1;
t>>=1;
}
ans=min(ans,cnt);
for(int j=0;j<k;j++){
st[i|(1<<j)]=st[i];//优化1
}
}
}
cout<<ans<<endl;
}
2)正解做法
把一个数组中的一个位置当作一个格子——处理偏移量
(x,y)
就代表在格子(x,y)-(x+1,y+1)
上
枚举状态时判断
左右走时是否有竖着的墙,
上下走时是否有横着的墙
3)01bfs(双端队列广搜)
Random
经典概率论知识
在[0,1]之间random可以看作均匀分布,期望就是 a + b 2 a+b\over\ 2 2a+b
最终操作相对于生成n-m个数,所以期望是
E ( ( n − m ) X ) = ( n − m ) E ( X ) = ( n − m ) 2 E((n-m)X)=(n-m)E(X)={(n-m)\over 2} E((n−m)X)=(n−m)E(X)=2(n−m)
Backpack
感谢恒哥的讲解,恒哥牛逼!!!
朴素做法:
f[i][j][k]
表示从前i个物品中选,异或和为j,体积为k的方案是否存在
转移方程:
f[i][j][k] = f[i-1][j^w][k-v] | f[i-1][j][k]
先明显三层循环,会超时
循环过程中f[i][j][k]
就是由f[i-1][j][k]
转移过来的,剩下的就是处理出f[i-1][j^w][k-v]
因为异或和枚举的是[0,1023],所以第二维[j^w]
相当于已经知道,只需要求出[k-v]
可以利用bitset压位优化第三维
bitset<N>f[i][j]
从前i个物品中选,异或和为j,体积为k的方案是否存在
第k个位置为1就说明方案存在
体积一维表示为一个二进制串,这样[k-v]
就可以用f[i]<<=v
一次算出来
const int N=1050;
bitset<N>f[N],g[N];
int n,m,k;
void solve(){
cin>>n>>m;k=1024;
for(int i=0;i<N;i++){
f[i].reset();
g[i].reset();
}
f[0][0]=1;
for(int i=1;i<=n;i++){
int v,w; cin>>v>>w;
for(int j=0;j<k;j++){
g[j]=f[j];
g[j]<<=v;
}
for(int j=0;j<k;j++){
f[j]|=g[j^w];
}
}
for(int i=k-1;i>=0;i--){
if(f[i][m]){
cout<<i<<endl;
return ;
}
}
cout<<-1<<endl;
}
Ball
同样是bitset的巧妙使用
可以先O(n^2)找出所有的两点之间距离,按照距离递增排序,
当枚举到第i条边时,我们只要找一下与这条边的两个端点ab距离大于i和小于i的所有点的方案,我们可以用bitset优化这个过程
p[i]表示与点i距离小于当前边的点的数量,取(p[a]^p[b]).count()
就能得到所有方案。
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
#define inf 0x3f3f3f3f
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define mod (int)1e9+7
#define NO puts("NO")
#define YES puts("YES")
#define No puts("No")
#define Yes puts("Yes")
using namespace std;
typedef pair<int,int>PII;
typedef long long ll;
const int N=2010,M=N*N;
int n,m;
int a[N],b[N];
bitset<N>bset[N];//表示当前枚举了哪些边
struct P{
int a,b,w;
bool operator<(const P&x)const{
return w<x.w;
}
}p[M];
int prim[M],tot;
bool vis[M];
void prime(int M){
vis[1]=1;//注意把1判定为非质数
for(int i=2;i<=M;i++){
if(!vis[i]) prim[tot++]=i;
for(int j=0;prim[j]<=M/i;j++){
vis[i*prim[j]]=1;
if(i%prim[j]==0) break;
}
}
}
int get(int i,int j){
return abs(a[i]-a[j])+abs(b[i]-b[j]);
}
inline void solve(){
cin>>n>>m;
for(int i=0;i<n;i++) bset[i].reset();
for(int i=0;i<n;i++) cin>>a[i]>>b[i];
int cnt=0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
p[cnt++]={i,j,get(i,j)};
}
}
sort(p,p+cnt);
int ans=0;
for(int i=0;i<cnt;i++){
int a=p[i].a,b=p[i].b,w=p[i].w;
if(!vis[w]) ans+=(bset[a]^bset[b]).count();
bset[a][b]=bset[b][a]=1;
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
// mp.reserve(1024);
// mp.max_load_factor(0.25);
prime(M);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
Path
分层图
const int N=1e6+10,M=2e6+10;
int n,m,s,k;
int h[N],e[M],ne[M],w[M],f[M],idx;
bool vis[N][2];
int dist[N][2],ch[N];
struct P{
int u,cnt,d;
bool operator<(const P&x)const{
return d>x.d;
}
};
priority_queue<P>q;
void init(){
idx=0;
for(int i=1;i<=n;i++){
h[i]=-1;
dist[i][1]=dist[i][0]=INF;
vis[i][1]=vis[i][0]=0;
ch[i]=0;
}
}
void add(int a,int b,int c,int d){
w[idx]=c,f[idx]=d,ne[idx]=h[a],e[idx]=b,h[a]=idx++;
}
void djs(){
set<int>S;
for(int i=1;i<=n;i++){
if(i!=s) S.insert(i);
}
dist[s][0]=0;
q.push({s,0,0});
int color=0;
while(q.size()){
P t=q.top();q.pop();
++color;
int u=t.u,cnt=t.cnt,d=t.d;
if(!cnt) S.erase(u);
else{
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
ch[j]=color;
}
vector<int>de;
for(auto i:S){
if(ch[i]!=color){
de.push_back(i);
dist[i][0]=dist[u][cnt];
q.push({i,0,dist[i][0]});
}
}
for(auto i:de) S.erase(i);
}
if(cnt) d-=k;
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(dist[j][f[i]]>d+w[i]){
dist[j][f[i]]=d+w[i];
q.push({j,f[i],dist[j][f[i]]});
}
}
}
}
inline void solve(){
cin>>n>>m>>s>>k;
init();
while(m--){
int a,b,c,d; cin>>a>>b>>c>>d;
add(a,b,c,d);
}
djs();
for(int i=1;i<=n;i++){
cout<<((min(dist[i][0],dist[i][1])==INF)?-1:min(dist[i][0],dist[i][1]))<<' ';
}
cout<<endl;
}