08-19考试总结

08-19考试总结

今天状态还可以

0819秘密通道 (portal)

  • 是一个玄学建图 \(+\) 最短路
  • 可惜考场上没想出来建图
  • 对于图上每一个点,我们将它与它上下左右方向能用子弹打到的地方连边
  • 然后对它相邻的点也正常连边,跑一边最短路
/*************************************************************************
    > File Name: portal.cpp
    > Author: Typedef 
    > Mail: 1815979752@qq.com 
    > Created Time: 2021-08-19 17:09:33
    > blog: https://www.cnblogs.com/Illyasviel
 ************************************************************************/
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N=5e2+7;
int n,m,a,b;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int d[N*N];
char s[N][N];
bool vis[N*N];
vector<pair<int,int> > son[N*N];
int getid(int x,int y){
    return m*(x-1)+y;
}
void add(int a,int b,int c){
    son[a].push_back(make_pair(b, c));
}
template<class T>void qread(T &x){
    x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    if(f) x=-x;
}
void buildmap(int x,int y){
    if(s[x][y]=='#') return;
    int a,b,c,d;
    int u=getid(x,y),w=INF;
    for(int i=x;i<=n;i++)
        if(s[i][y]=='#'){
            a=getid(i-1,y),w=min(w,i-x);
            break;
        }
    for(int i=x;i;i--)
        if(s[i][y]=='#'){
            b=getid(i+1,y),w=min(w,x-i);
            break;
        }
    for(int i=y;i<=m;i++)
        if(s[x][i]=='#'){
            c=getid(x,i-1),w=min(w,i-y);
            break;
        }
    for(int i=y;i;i--)
        if(s[x][i]=='#'){
            d=getid(x,i+1),w=min(w,y-i);
            break;
        }
    add(u,a,w),add(u,b,w),add(u,c,w),add(u,d,w);
    return;
}
void connect(int ux,int uy,int vx,int vy){
    if(s[vx][vy]=='#') return;
    add(getid(ux,uy),getid(vx,vy),1);
}
queue<int> q;
void SPFA(int s){
    memset(d,0x3f,sizeof(d));
    d[s]=0;
    q.push(s);
    vis[s]=true;
    while(!q.empty()){
        int u=q.front();
        vis[u]=0;
        q.pop();
        for(unsigned int i=0;i<son[u].size();i++){
            int v=son[u][i].first,w=son[u][i].second;
            if(d[u]+w<d[v]){
                d[v]=d[u]+w;
                if(!vis[v]) q.push(v),vis[v]=1;
            }
        }
    }
    return;
}
int main(){
    qread(n),qread(m);
    for(int i=1;i<= n;i++) scanf("%s",s[i]+1);
    for(int i=2;i<n;i++)
        for(int j=2;j<m;j++){
            if(s[i][j]=='#') continue;
            for(int k=0;k<4;k++){
                int x=i+dx[k],y=j+dy[k];
                buildmap(i,j);
                connect(i,j,x,y);
            }
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(s[i][j]=='C') a=getid(i,j);
            if(s[i][j]=='F') b=getid(i,j);
        }
    SPFA(a);
    if(d[b]==INF) puts("nemoguce");
    else printf("%d\n",d[b]);
    return 0;
}

0819购物 (shopping)

  • 嗯,怎么说呢,是一个带有一点反悔功能的贪心
  • 首先,如果你手上的钱不多,连优惠后都卖不够前 \(k\) 个最便宜的,那么就尽量多的卖就行了
  • 然后,如果你买了前 \(k\) 个折后最便宜的,手上还有钱剩下的话,那就先把剩下的按原价排序
  • 然后,把你前 \(k\) 个打过折的,按照省钱的多少,丢到小根堆里
  • 每次去除最不能省钱的,把他换成你这个最便宜的试试看,是否能更新答案
/*************************************************************************
    > File Name: portal.cpp
    > Author: Typedef 
    > Mail: 1815979752@qq.com 
    > Created Time: 2021-08-19 07:32:30
    > blog: https://www.cnblogs.com/Illyasviel
 ************************************************************************/
#include<bits/stdc++.h>
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
const int N=5e4+7;
template<class T>void qread(T &x){
    x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    if(f) x=-x;
}
ll n,m,k,res;
struct Node{
    ll p,q;
    friend bool operator<(const Node &a,const Node &b){
        return a.q<b.q;
    }
}a[N];
ll ori[N];
ll cnt=0,pos=0,idx=0,j=0;
priority_queue<ll,vector<ll>,greater<ll> > q;
int main(){
    qread(n),qread(k),qread(m);
    for(int i=1;i<=n;i++){
        ll x,y;
        qread(x),qread(y);
        a[i]={x,y};
    }
    res=m;
    sort(a+1,a+n+1);
    for(int i=k+1;i<=n;i++) ori[++idx]=a[i].p;
    for(int i=1;i<=k;i++){
        if(res>=a[i].q){
            res-=a[i].q,cnt++,pos=i;
            q.push(a[i].p-a[i].q);
        }
        else break;
    }
    if(pos!=k){
        printf("%lld\n",cnt);
        return 0;
    }
    j=1,pos++;
    sort(ori+1,ori+idx+1);
    while(res>=0&&(j<=idx||pos<=n)){
        ll pnow=q.top();
        ll pmin=min(ori[j],a[pos].q+pnow);
        if(res>=pmin){
            if(pmin==ori[j]){
                res-=ori[j];
                cnt++,j++;
                if(j>idx) ori[j]=INF;
                if(cnt==n) break;
            }
            else{
                q.pop();
                res-=a[pos].q+pnow,cnt++;
                q.push(a[pos].p-a[pos].q);
                pos++;
            }
        }
        else break;
    }
    printf("%lld\n",cnt);
    return 0;
}

0819拆网线 (tree)

  • 看题目的要求,发现一个类似匹配的东西能使答案最优
  • 于是我就跑了个树形DP
  • f[i][1/0] 表示在 \(i\) 点选或不选的情况下,需要保留网线的数量
  • 不过据说有一种贪心做法,从树的底部开始往上放,放到不能放为止
  • 也有人写的其他做法
/*************************************************************************
    > File Name: portal.cpp
    > Author: Typedef 
    > Mail: 1815979752@qq.com 
    > Created Time: 2021-08-19 07:32:30
    > blog: https://www.cnblogs.com/Illyasviel
 ************************************************************************/
#include<bits/stdc++.h>
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
const int N=5e4+7;
template<class T>void qread(T &x){
    x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    if(f) x=-x;
}
ll n,m,k,res;
struct Node{
    ll p,q;
    friend bool operator<(const Node &a,const Node &b){
        return a.q<b.q;
    }
}a[N];
ll ori[N];
ll cnt=0,pos=0,idx=0,j=0;
priority_queue<ll,vector<ll>,greater<ll> > q;
int main(){
    qread(n),qread(k),qread(m);
    for(int i=1;i<=n;i++){
        ll x,y;
        qread(x),qread(y);
        a[i]={x,y};
    }
    res=m;
    sort(a+1,a+n+1);
    for(int i=k+1;i<=n;i++) ori[++idx]=a[i].p;
    for(int i=1;i<=k;i++){
        if(res>=a[i].q){
            res-=a[i].q,cnt++,pos=i;
            q.push(a[i].p-a[i].q);
        }
        else break;
    }
    if(pos!=k){
        printf("%lld\n",cnt);
        return 0;
    }
    j=1,pos++;
    sort(ori+1,ori+idx+1);
    while(res>=0&&(j<=idx||pos<=n)){
        ll pnow=q.top();
        ll pmin=min(ori[j],a[pos].q+pnow);
        if(res>=pmin){
            if(pmin==ori[j]){
                res-=ori[j];
                cnt++,j++;
                if(j>idx) ori[j]=INF;
                if(cnt==n) break;
            }
            else{
                q.pop();
                res-=a[pos].q+pnow,cnt++;
                q.push(a[pos].p-a[pos].q);
                pos++;
            }
        }
        else break;
    }
    printf("%lld\n",cnt);
    return 0;
}

0819密室 (room)

  • 状压 \(+\) bfs转移
  • 把当前的钥匙持有情况压缩到状态里
  • f[i][j] 表示当前钥匙持有情况为 \(i\) ,到达 \(j\) 点,所用的最少传送门的数量
/*************************************************************************
    > File Name: room.cpp
    > Author: Typedef 
    > Mail: 1815979752@qq.com 
    > Created Time: 2021-08-19 10:04:22
    > blog: https://www.cnblogs.com/Illyasviel
 ************************************************************************/
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N=6e3+7;
int d[N];
bool vis[1<<11][N];
int h[N],e[N<<1],ne[N<<1],key[N<<1];
int st[N];
int f[1<<11][N];
int idx=0;
int n,m,k;
void add(int a,int b,int c){
    e[idx]=b;
    ne[idx]=h[a];
    key[idx]=c;
    h[a]=idx++;
}
struct Node{
    int u,key;
};
queue<Node> q;
template<class T>void qread(T &x){
    x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    if(f) x=-x;
}
int ans=INF;
int main(){
    memset(h,-1,sizeof(h));
    qread(n),qread(m),qread(k);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=k;j++){
            int x;
            qread(x);
            st[i]<<=1,st[i]+=x;
        }
    for(int i=1;i<=m;i++){
        int K=0,x,y;
        qread(x),qread(y);
        for(int j=1;j<=k;j++){
            int X;
            qread(X);
            K<<=1;
            K+=X;
        }
        add(x,y,K);
    }
    memset(f,0x3f,sizeof(f));
    f[st[1]][1]=0;
    vis[st[1]][1]=1;
    q.push({1,st[1]});
    while(!q.empty()){
        int u=q.front().u,ukey=q.front().key;
        q.pop();
        vis[ukey][u]=false;
        for(int i=h[u];~i;i=ne[i]){
            int v=e[i];
            int vkey=ukey|st[v];
            if((key[i]&ukey)==key[i]&&f[vkey][v]>f[ukey][u]+1){
                f[vkey][v]=f[ukey][u]+1;
                if(!vis[vkey][v]) vis[vkey][v]=true,q.push({v,vkey});
            }
        }
    }
    for(int i=0;i<(1<<k);i++) ans=min(ans,f[i][n]);
    if(ans==INF) puts("No Solution");
    else printf("%d\n",ans);
    return 0;
}
posted @ 2021-08-19 18:06  actypedef  阅读(52)  评论(0)    收藏  举报