OI 笑传 #8

都是比较简单的题哦,目标是练习代码能力,一遍写对。

ABC126E 1 or 2

点权只有 \(1,2\) ,把给的事实当成图,同一个连通块内的点只需要知道一个点就可以推出所有点,连通块计数即可。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
const int N=1e5+555;
vector<int> e[N];
int cnt=0;
bitset<N> vis;
void dfs(int u){
  vis[u]=1;
  for(int v:e[u])if(!vis[v])dfs(v);
}
int main(){
  
  int n,m;cin>>n>>m;
  for(int i=1;i<=m;i++){
    int x,y,z;cin>>x>>y>>z;
    e[x].push_back(y);e[y].push_back(x);
  }
  for(int i=1;i<=n;i++){
    if(!vis[i]){
      cnt++;
      dfs(i);
    }
  }
  cout<<cnt;
  
  return 0;
}

ABC400D Takahashi the Wall Breaker

按照题目要求网格图里面无脑建图跑 dijkstra 即可。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
const int N=1200;
char mp[N][N];
int n,m;
int rr(int x,int y){return (x-1)*n+y;}
struct work{
  int v;int w;
  bool operator<(const work &x)const{
    return x.w<w;
  }
};
vector<work> e[N*N];
int dis[N*N];
bitset<N*N> vis;
void dij(int s){
  priority_queue<work> q;
  memset(dis,0x3f,sizeof dis);
  dis[s]=0;
  q.push(work{s,0});
  while(q.size()){
    int u=q.top().v;
    int w=q.top().w;
    q.pop();
    if(vis[u])continue;
    vis[u]=1;
    dis[u]=w;
    for(work to:e[u]){
      int v=to.v;
      int w=to.w;
      if(dis[v]>dis[u]+w){
        dis[v]=dis[u]+w;
        q.push(work{v,dis[v]});
      }
    }
  }
  return ;
}
int main(){
  
  cin>>n>>m;
  for(int i=1;i<=n;i++){
    string pt;cin>>pt;
    for(int j=1;j<=m;j++){
      mp[i][j]=pt[j-1];
    } 
  }
  for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
      int t=rr(i,j);
      bool gob=0;
      bool isb=0;
      for(int ri=i-1,cnt=1;ri>=1 && cnt<=2;ri--,cnt++){
        if(mp[ri][j]=='#')gob=1;
        e[t].push_back(work{rr(ri,j),gob|isb});
        // cerr<<"link "<<i<<' '<<j<<" to "<<ri<<' '<<j<<' '<<(gob|isb)<<'\n';
      }
      gob=0;
      for(int ri=i+1,cnt=1;ri<=n && cnt<=2;ri++,cnt++){
        if(mp[ri][j]=='#')gob=1;
        e[t].push_back(work{rr(ri,j),gob|isb});
        // cerr<<"link "<<i<<' '<<j<<" to "<<ri<<' '<<j<<' '<<(gob|isb)<<'\n';
      }
      gob=0;
      for(int rj=j-1,cnt=1;rj>=1 && cnt<=2;rj--,cnt++){
        if(mp[i][rj]=='#')gob=1;
        e[t].push_back(work{rr(i,rj),gob|isb});
        // cerr<<"link "<<i<<' '<<j<<" to "<<i<<' '<<rj<<' '<<(gob|isb)<<'\n';
      }
      gob=0;
      for(int rj=j+1,cnt=1;rj<=m && cnt<=2;rj++,cnt++){
        if(mp[i][rj]=='#')gob=1;
        e[t].push_back(work{rr(i,rj),gob|isb});
        // cerr<<"link "<<i<<' '<<j<<" to "<<i<<' '<<rj<<' '<<(gob|isb)<<'\n';
      }
    }
  }
  int bx,by,ex,ey;cin>>bx>>by>>ex>>ey;
  int s=rr(bx,by);
  int t=rr(ex,ey);
  dij(s);
  cout<<dis[t];

  return 0;
}

AGC032A Limited Insertion

算个小思维吧。

拿到这题就想要模拟加数的过程,不好模拟于是我们模拟删数。第一次想的是从前往后选,贪心删最前面的。

但是想想就知道这样不对啊,从后往前是对的,因为对前面的数没有影响,是更优的。

写的时候也没考虑从后往前的正确性,就是感觉这样能完美模拟加入的过程,觉得很对就写了。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
int arr[1004];
bitset<1004> bit;
int main(){
  
  int n;cin>>n;
  stack<int> del;
  for(int i=1;i<=n;i++){
    cin>>arr[i];
  }
  for(int i=1;i<=n;i++){
    vector<pair<int,int> > at;
    for(int j=1;j<=n;j++){
      if(!bit[j])at.push_back(mkp(arr[j],j));
    }
    int ps=at.size()-1;
    while(ps>=0&&ps+1!=at[ps].first){
      ps--;
    }
    if(ps==-1){
      cout<<-1;
      return 0;
    }
    bit[at[ps].second]=1;
    del.push(at[ps].first);
  }
  while(del.size()){cout<<del.top()<<'\n';del.pop();}
  
  return 0;
}

Luogu P1433

很板的状态压缩 DP,一遍写过。

但是要注意输入的坐标也有可能是浮点数。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
struct ps{
  double x;double y;
}p[100];
double dp[(1<<16)][20];
double dis(int i,int j){
  return sqrt(abs(p[i].x-p[j].x)*abs(p[i].x-p[j].x)+abs((p[i].y-p[j].y))*abs(p[i].y-p[j].y));
}
int main(){
  
  int n;cin>>n;
  int exi=0;
  for(int i=1;i<=n;i++){
    cin>>p[i].x>>p[i].y;
    if(p[i].x==0&&p[i].y==0)exi=i;
  }
  for(int i=0;i<=(1<<n);i++){
    for(int j=0;j<=n;j++)dp[i][j]=0x3f3f3f3f;
  }
  int beg=0;
  if(exi){
    beg|=(1<<(exi-1));
    dp[beg][exi]=0;
  }
  for(int i=1;i<=n;i++){
    if(i==exi)continue;
    dp[beg|(1<<(i-1))][i]=dis(0,i);
  }
  for(int i=0;i<(1<<n);i++){
    for(int j=1;j<=n;j++){
      if((!(i>>(j-1))&1))continue;
      for(int k=1;k<=n;k++){
        if((i>>(k-1))&1)continue;
        dp[i|(1<<(k-1))][k]=min(dp[i][j]+dis(k,j),dp[i|(1<<(k-1))][k]);
      }
    }
  }
  double ans=0x3f3f3f3f;
  for(int i=1;i<=n;i++){
    ans=min(ans,dp[(1<<n)-1][i]);
  }
  cout<<fixed<<setprecision(2)<<ans;

  return 0;
}

Luogu P2111

似乎是个 DP,但是这里我们写暴搜。

由于 \(n,q\) 的大小差距很小,考虑钦定 \(0 \sim n-q\) 个位置小红是错的,遍历一遍就能算出概率,各个情况是独立的直接相加即可。

\(\dbinom{50}{5}\) 也只是 \(10^6\) 级别,搜索跑的飞快。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
string ts;
double ans=0;
double swit=1;
double tc=0;
double cor;
double incor;
int n,a,q;
bitset<100> vis;
void dfs(int u,int lm,int swi){
  if(u>n)return;
  vis[u]=1;
  if(swi+1==lm){
    double tk=1;
    for(int i=1;i<=n;i++){
      if(vis[i]){
        if(ts[i]=='1')tk=tk*incor;
        if(ts[i]=='0')tk=tk*cor;
      }
      else{
        if(ts[i]=='1')tk=tk*cor;
        if(ts[i]=='0')tk=tk*incor;
      }
    }
    tc=tc+tk;
  }
  else dfs(u+1,lm,swi+1);
  vis[u]=0;
  dfs(u+1,lm,swi);
  return ;
}

int main(){
  
  cin>>n>>a>>q;
  if(!q){
    cout<<fixed<<setprecision(3)<<(double)1.000;
    return 0;
  }
  cor=1.0*a/100;incor=1-cor;
  cin>>ts;
  ts=' '+ts;
  for(int i=0;i<=n-q;swit=swit*1.0/(1.0*(n-i)),i++){
    tc=0;
    if(i==0){
      tc=1;
      for(int j=1;j<=n;j++){
        if(ts[j]=='1')tc=tc*cor;
        else tc=tc*incor;
      }
      ans=ans+tc;
      continue;
    }
    dfs(1,i,0);
    ans=ans+tc;
  }
  cout<<fixed<<setprecision(3)<<ans;
  
  return 0;
}

Luogu P3854

想了一会感觉不会什么很巧妙的方法于是上了个圆方树+树链剖分的写法,竟然一次写对了。

其实有很巧妙的判断边不带权的树上一点是否在两点简单路径上的方法,我们令路径为 \((u,v)\),树上有一点 \(t\)\(t\)\((u,v)\) 的简单路径上当且仅当 \(\operatorname{dis}(u,v)=\operatorname{dis}(u,t)+\operatorname{dis}(v,t)\)。其中 \(\operatorname{dis}(u,v)\) 定义为 \(u,v\) 在树上的简单路径经过边的数量。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
const int N=1e5+5;
const int lgr=24;
struct lsqxx{
  int u,v,nxt;
}e[N*6];
int id=-1;
int _head[N];
void add(int u,int v){
  id++;
  e[id].u=u;e[id].v=v;
  e[id].nxt=_head[u];
  _head[u]=id;
  return;
}
int dfn[N],low[N];
vector<int> col[N];
stack<int> s;
int idx=0;
int vdcc=0;
void tarjan(int u,int fa){
  dfn[u]=low[u]=++idx;
  s.push(u);
  for(int i=_head[u];~i;i=e[i].nxt){
    int v=e[i].v;
    if(fa==(i^1))continue;
    if(!dfn[v]){
      tarjan(v,i);
      low[u]=min(low[u],low[v]);
      if(dfn[u]<=low[v]){
        vdcc++;
        col[vdcc].push_back(u);
        while(s.top()!=v){
          int vv=s.top();s.pop();
          col[vdcc].push_back(vv);
        }
        s.pop();
        col[vdcc].push_back(v);
      }
    }
    else{
      low[u]=min(low[u],dfn[v]);
    }
  }
}
vector<int> edge[N];
ll siz[N];int n,m;
vector<int> cp;
int dep[N];
int fa[N][30];
void bfs(int s){
  memset(dep,0x3f,sizeof dep);
  queue<int> q;
  q.push(s);
  dep[0]=0;dep[s]=1;
  fa[0][0]=0;fa[s][0]=0;
  while(q.size()){
    int u=q.front();
    q.pop();
    for(int v:edge[u]){
      if(dep[v]>dep[u]+1){
        dep[v]=dep[u]+1;
        q.push(v);
        fa[v][0]=u;
        for(int j=1;j<=lgr;j++){
          fa[v][j]=fa[fa[v][j-1]][j-1];
        }
      }
    }
  }
  return ;
}
struct treed{
  int dfn;
  int son;
  int siz;
  int fa;
  int dep;
  int top;
}td[N];
void dfs1(int u,int fa){
  td[u].fa=fa;
  td[u].dep=td[fa].dep+1;
  td[u].siz=1;
  int maxsub=0;
  for(int i=0;i<edge[u].size();i++){
    int v=edge[u][i];
    if(v==fa)continue;
    dfs1(v,u);
    td[u].siz+=td[v].siz;
    if(td[v].siz>maxsub){
      maxsub=td[v].siz;
      td[u].son=v;
    }
  }
  return ;
}
int idxx=0;
void dfs2(int u,int top){
  td[u].dfn=++idxx;
  td[u].top=top;
  if(!td[u].son)return ;
  dfs2(td[u].son,top);
  for(int i=0;i<edge[u].size();i++){
    int v=edge[u][i];
    if(v==td[u].fa||v==td[u].son)continue;
    dfs2(v,v);
  }
}
struct seg{
  int l;int r;
  bool v;
}t[N<<2];
void b(int p,int l,int r){
  t[p].l=l;t[p].r=r;
  if(l==r){
    t[p].v=0;
    return ;
  }
  int mid=l+r>>1;
  b(ls,l,mid);b(rs,mid+1,r);
  return ;
}
void asi(int p,int pos,bool st){
  if(t[p].l==t[p].r&&t[p].l==pos){
    t[p].v=st;return ;
  }
  int mid=t[p].l+t[p].r>>1;
  if(pos<=mid)asi(ls,pos,st);
  if(mid<pos) asi(rs,pos,st);
  t[p].v=t[ls].v|t[rs].v;
  return;
}
bool qry(int p,int l,int r){
  if(l<=t[p].l&&t[p].r<=r){
    return t[p].v;
  }
  int mid=t[p].l+t[p].r>>1;
  if(l<=mid&&mid<r){
    return qry(ls,l,r)|qry(rs,l,r);
  }
  if(l<=mid)return qry(ls,l,r);
  if(mid<r) return qry(rs,l,r);
  return 0;
}
bool j(int u,int v){
  bool isok=0;
  while(td[u].top!=td[v].top){
    if(td[td[u].top].dep<=td[td[v].top].dep)swap(u,v);
    isok|=qry(1,td[td[u].top].dfn,td[u].dfn);
    u=td[td[u].top].fa;
  }
  if(td[u].dep>td[v].dep)swap(u,v);
  isok|=qry(1,td[u].dfn,td[v].dfn);
  return isok;
}
int main(){
  
  memset(_head,-1,sizeof _head);
  cin>>n>>m;
  for(int i=1;i<=m;i++){
    int u,v;cin>>u>>v;
    add(u,v);add(v,u);
  }
  tarjan(1,-1);
  for(int i=1;i<=vdcc;i++){
    for(int v:col[i]){
      edge[i+n].push_back(v);
      edge[v].push_back(i+n);
      // cerr<<"g "<<i+n<<' '<<v<<'\n';
    }
  }
  b(1,1,n+vdcc);
  dfs1(1,0);dfs2(1,1);
  int q;cin>>q;
  for(int i=1;i<=q;i++){
    int c,u,v;cin>>u>>v>>c;
    asi(1,td[c].dfn,1);
    if(j(u,v))cout<<"yes"<<'\n';
    else cout<<"no"<<'\n';
    asi(1,td[c].dfn,0);
  }
  
  return 0;
}
posted @ 2025-08-10 15:44  hm2ns  阅读(29)  评论(0)    收藏  举报