20181029 考试记录

题目pdf

W神爷的题解

T1:简单$dfs$

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
    int f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
int a1[80],b1[80],a2[80],b2[80];
int n,m,num[102];
bool check(){
    int ans=0;
    for(int i=0;i<=12;i++){
        if(num[i]>0) ans+=num[i];
        if(!num[i]) break;
    }
    if(ans==n+m) return 1;
    return 0;
}
void dfs(int pos)
{
    if(check()){
        cout<<"Yes";
        exit(0);
        return;
    } 
    if(pos==m+1) return;
    if(!a2[pos]) {
        dfs(pos+1);
        return;
    }
    dfs(pos+1);
    for(int i=1;i<=n;i++){
        if(b1[i]!=0){
            int t2=b2[pos],t1=b1[i];num[b1[i]]--;num[b2[pos]]--;
            b1[i]-=a2[pos];
            if(b1[i]<0) b1[i]=0;
            num[b1[i]]++;
            b2[pos]-=a1[i];
            if(b2[pos]<0) b2[pos]=0;
            num[b2[pos]]++;
            
            dfs(pos+1);
            num[b2[pos]]--;
            num[b1[i]]--;
            b1[i]=t1;
            b2[pos]=t2;
            num[b2[pos]]++;
            num[b1[i]]++;
            
        }
    }
} 
int main()
{
    freopen("defile.in","r",stdin);
    freopen("defile.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n;i++) a1[i]=read(),b1[i]=read(),num[b1[i]]++;
    for(int i=1;i<=m;i++) a2[i]=read(),b2[i]=read(),num[b2[i]]++;
    dfs(1);
    cout<<"No";
    return 0;
}
View Code

T2:

(垃圾题目,$getchar$换成$scanf$,就$100 score$了)

$k\leq 15$,所以想到可以用状压$dp$来解决,第一步是要求每两个宝藏之间的距离,假设起点也是一个宝藏,用$bfs$解决,然后问题就转换成在一个完全图中选择$x$个点,使经过一次后距离不超过$T$,最大的$x$是多少。所以考虑状压$dp$,但是当只有一位($dp(i)$ 表示当前状态时是有后效性的,所以考虑二维)。

设$dp(i,j)$表示当前取到的状态为$i$,最后一个点是$j$的最小距离。然后看一下当前距离是否小于$t$,若小于然后统计一下状态里的$1$即可.$dp(i,j)=dp(u,p)+dis(p,j) $,然后就瞎搞了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
inline int read()
{
    int f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
int n,m,k,t;
int a[512][512];
struct node{
    int x,y;
}p[21];
int sx,sy,sry=1,has[512][512],vis[512][512],dis[21][21];
struct node1{
    int x,y,ans;
};
queue<node1> que;
int dx[4]={1,-1,0,0};
char str1[510];
int dy[4]={0,0,1,-1};
int dp[125537][21],d[21],inf=99999999,ans;
int main()
{
    n=read(),m=read(),k=read(),t=read();
    for(int i=1;i<=n;i++){
        scanf("%s",str1+1);
        for(int j=1;j<=m;j++){
            char str=str1[j];
            if(str=='#') a[i][j]=0;
            else a[i][j]=1;
            if(str=='*'){p[++sry].x=i,p[sry].y=j;has[i][j]=sry;}
            if(str=='S'){p[1].x=i,sx=i,sy=j,p[1].y=j;has[i][j]=1;}
        }
        getchar(); 
    }
    memset(dis,127/3,sizeof(dis));
    for(int st=1;st<=sry;st++){
        int px=p[st].x,py=p[st].y;
        memset(vis,0,sizeof(vis));
        while(!que.empty()) que.pop();
        node1 pig;
        pig.ans=0,pig.x=px,pig.y=py;
        vis[px][py]=1;
        que.push(pig);
        while(!que.empty()){
            int xx=que.front().x,yy=que.front().y,ff=que.front().ans;que.pop();
            for(int i=0;i<4;i++){
                int tx=dx[i]+xx,ty=dy[i]+yy;
                if(tx>=1&&tx<=n&&ty>=1&&ty<=m){
                    if(vis[tx][ty]) continue;
                    if(!a[tx][ty]) continue;
                    vis[tx][ty]=1;
                    node1 fff;
                    fff.x=tx,fff.y=ty,fff.ans=ff+1;
                    que.push(fff);
                    if(has[tx][ty]){
                        dis[st][has[tx][ty]]=fff.ans;
                    }
                }
            }
        }
    }
    memset(dp,127/3,sizeof(dp));
    dp[1][1]=0;
    for(int i=1;i<=(1<<sry)-1;i++){
        memset(d,0,sizeof(d));
        int st=0;
        for(int j=1;j<=sry;j++){
            if(i&(1<<(j-1))) d[j]=1,st++;
        }
        for(int j=1;j<=sry;j++){
            if(!d[j]) continue;
            d[j]=0;
            int zz=0,disdis=inf;
            for(int z=1;z<=sry;z++) zz+=(d[z]*(1<<(z-1))); 
            for(int z=1;z<=sry;z++){
                if(d[z]) dp[i][j]=min(dp[i][j],dp[zz][z]+dis[z][j]);
            }
            d[j]=1;
            if(dp[i][j]<=t) 
                ans=max(ans,st);
        }
    }
    cout<<ans-1<<endl;
}
View Code

T3:

其实就是一道比较简单的$dp$,结果看错了$A_i$的范围

首先,先离散化,lower_bound即可,确定一下每个数,就是把他们存到$1~n$中。然后看见题目上说的是最小的最大,果断二分答案。我们假设$x$为二分的最小值,所以对于每一个位置$pos$,我们先设$st[pos]$表示右端点为$pos$的最小$l$值满足在$l~pos$中没有相同的数,其实就是这道题(this)。所以$pos$上一块的取值范围是$[st[pos]-1,pos-i]$,我们设$g(i)$表示前$i$个音符已经划定的方案数,及从$\sum_{i=l}^r g(i)$,当前复杂度$O(n^2)$,考虑到$\sum_{i=l}^r g(i)$这个式子可以前缀和优化,所以$dp$总复杂度$O(n)$,时间复杂度:$O(nlog(n))$

#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 998244353
#include<algorithm>
#define int long long
using namespace std;
inline int read()
{
    int f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
int g[525011],sumg[525011],n,a[525011],x[525011],st[525011],last[525011];
inline int get(int lim){
    memset(g,0,sizeof(g)),memset(sumg,0,sizeof(sumg));
    g[0]=sumg[0]=1;
    for(int i=1;i<=n;i++){
        int l=st[i]-1,r=i-lim;
        if(l>r) g[i]=0;
        else{
            if(l==0) g[i]=sumg[r];
            else g[i]=sumg[r]-sumg[l-1];
        }
        g[i]=(g[i]+mod)%mod;
        sumg[i]=sumg[i-1]+g[i];
        sumg[i]=(sumg[i]+mod)%mod;
    }return g[n]%mod;
}
bool check(int mid){return get(mid);}
int maxn;
signed main()
{
    freopen("instrument.in","r",stdin);
    freopen("instrument.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++) x[i]=a[i]=read();
    sort(x+1,x+n+1);
    for(int i=1;i<=n;i++) a[i]=lower_bound(x+1,x+n+1,a[i])-x;
    for(int i=1;i<=n;i++){
        st[i]=max(st[i-1],last[a[i]]+1);
        last[a[i]]=i;
    }
    int l=1,r=n;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid)) maxn=max(maxn,mid),l=mid+1;    
        else r=mid-1;
    }
    cout<<maxn<<endl<<(get(maxn)+mod)%mod;
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/si-rui-yang/p/9872466.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值