jzyz 题库 题目选做

题库中也有很多我想不出来的模拟赛的题目。做还是必要的。做自己的题目 时间很紧 想想自己的文化课 我又没有那么强 我必须得刷.

LINK:水题一道

发现是一道计数题 计数题拿高分的才是王者,但是 计数题不取模就是在耍流氓了...好久没写高精了 顺便写写。

此题 我们发现 不管怎么搞每个教室都需要两个人我们不妨 先让m-=2*n; 然后就是剩下的m个人的分配问题了 感觉是组合数其实并不尽然。因为显然不对...

这样 对于一个人来说他有n种可能 那么m个人呢?m^n 但是显然有重复如第一个人选第二个 第二个人选第一个 和第一个人选第一个第二个人选第二个这样是等效的...

考虑排列数对我们答案的影响,不管排列的话其实除以一个m!即可。然后成功想错 这样的做法是错误的。因为这有重复除以m!根本什么也不是。。。没有什么排列数...

正解是隔板法 再次隔板 设当前人数为 s=m-2*n 那么其实有将s个人分到n个房间中 且每个房间总和为s 也就是说 x1+x2+x3+x4+...=s 这显然是隔板法了...

注意到x可能为0 所以再补板n-1 空隙 还是插板n-1个即可。m为500 用头想都是高精。C(s+n-1,n-1) 。。。想10min都没怎么发现这个模型藏得有点深。

约分是必要的 分解质因数再约分 就变成高精乘单精了。

//#include
#include
#include
#include 
#include
#include<string>
#include
#include
#include
#include
#include
#include
#include
#include
#include<set>
#include
#include
#include
#include
#define ll long long
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=1010;
int s0,s1,s2;
int p0[MAXN],p1[MAXN],p2[MAXN];
int b[MAXN],top;
int n,m,s,c;
inline void insert(int x,int *a)
{
    int s=x;
    for(int i=2;i*i<=x;++i)
        while(s%i==0)
        {
            s=s/i;
            ++a[i];
        }
    if(s>1)++a[s];
}
inline void mul(int x)
{
    int res=0;
    for(int i=1;i<=top;++i)
    {
        b[i]=b[i]*x;
        b[i]+=res;
        res=b[i]/10;
        b[i]=b[i]%10;
    }
    while(res)
    {
        b[++top]=res;
        res=b[top]/10;
        b[top]=b[top]%10;
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    if(m<2*n){puts("0");return 0;}
    s=m-2*n+n-1;c=n-1;//求 C(s,c);
    for(int i=2;i<=s;++i)insert(i,p0);
    for(int i=2;i<=c;++i)insert(i,p1);
    for(int i=2;i<=s-c;++i)insert(i,p2);
    b[++top]=1;
    for(int i=2;i<=s;++i)
    {
        p0[i]=p0[i]-p1[i]-p2[i];
        while(p0[i])
        {
            --p0[i];
            mul(i);
        }
    }
    for(int i=top;i>=1;--i)printf("%d",b[i]);
    return 0;
}
View Code

 LINK:免费馅饼

咕了 这么长时间了 也该写写了... 看起来很显然是dp 但是还要输出方案...(那也很水

第一次写状态转移写错了 ,惊了 瞎写了一个状态转移..感觉不太对..当然f[i][j]表示第i秒到了第j个位置的最大价值 f[i][j]=max(f[i-1][j-1],f[i-1][j-2]...)然后 馅饼的话开vector记录下来,到达这个位置就累加上价值即可。

有一个坑点是 对于一个馅饼 下降高度为 h-1 题目中说道 恰好在某一秒末和人相遇才行也就是 h-1%v!=0的都不能要。还有一个坑点是 方案要从最后一个馅饼开始找而不是最后一秒开始...

//#include
#include
#include
#include
#include
#include<string>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include<set>
#include
#include
#define INF 1000000000
#define ll long long
#define R register
#define db double
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int MAXN=110,maxn=2010;
int n,m,cnt,maxx,ans;
int st[MAXN],top;
struct wy
{
    int s,x,v,p;
}t[maxn];
int f[maxn][MAXN];//f[i][j]表示第i秒在x这个位置所能获得的最大分数
int w[maxn][MAXN];
vector<int>g[maxn];
inline int abs(int x){return x>0?x:-x;}
inline void get_path(int x,int y)
{
    if(!x)return;
    st[++top]=-(w[x][y]-y);
    get_path(x-1,w[x][y]);
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    int s,x,v,p,h=m;--h;
    while(scanf("%d",&s)==1)
    {
        x=read();v=read();p=read();
        if(h%v!=0)continue;
        t[++cnt]=(wy){s,x,v,p};
        int st=s+h/v;
        g[st].push_back(cnt);
        maxx=max(maxx,st);
    }
    memset(f,0xcf,sizeof(f));
    f[0][(n>>1)+1]=0;
    for(int i=1;i<=maxx;++i)
    {
        for(int j=1;j<=n;++j)
        {
            for(int k=max(1,j-2);k<=min(n,j+2);++k)
            {
                if(f[i][j]1][k])
                {
                    f[i][j]=f[i-1][k];
                    w[i][j]=k;
                }
            }
        }
        for(int k=0;k<(int)g[i].size();++k)
            {
                int r=g[i][k];
                f[i][t[r].x]+=t[r].p;
            }
    }
    for(int i=1;i<=n;++i)ans=max(ans,f[maxx][i]);
    printf("%d\n",ans);
    for(int i=1;i<=maxx;++i)
    {
        for(int j=1;j<=n;++j)
        {
            if(f[i][j]==ans)
            {
                get_path(i,j);
                for(int k=top;k>=1;--k)printf("%d\n",st[k]);
                return 0;
            }
        }
    }
    return 0;
}
View Code

 update :其实这个也可以不用vector存我们利用排序后时间从大到小的顺序便利整个数组即可 省掉空间和时间...

LINK:字符合并

早就想写这道题了 受不了了 这道题 是水题..我坚信。(然后想了30min 被打脸...

还是 字符串之间进行合并 值得一提的是这次只有01串 每k个字符可以合成一个字符 存在一个命题是 如果(n-1)%(k-1)==0的话那么则有 最后合并剩下一个字符 (我也不知道是怎么证明的..

首先还是设计状态吧 反正是区间dp 转移着实有点困难 但在我坚持不懈的努力之下 还是成功的进行转移了 但是不知道对不对 感觉正确性还是有的..

f[i][j][k]表示 由i到j状态为k的最大 代价 那么转移就是区间dp 然后 枚举断点 唯一不同的是还需要枚举左边状态s1 右边状态s2 然后merge一下即可 merge有点难写 但是仔细思考还是可以O(1)的...

但是这样的复杂度是n^3*2^k*2^k=n^3*4^k; 显然过不了1e12 。

这里先放暴力(我不知道对不对 不想交):发现暴力是瞎写的 不放了

当然 我觉得这个merge写的还算很精辟/cy.(精辟锤子 写错了。

考虑优化一个比较显然的地方是每次我们枚举状态的时候其实不必要枚举到1<<(k-1) 因为对于一个区间来说其固定的状态大小是存在的 (n-1)%(k-1)+1其实就是这个东西了...每8次一循环每个循环的复杂度是2^1-1+2^2-1+...2^7-1加起来是2^8那么这样其实复杂度骤降8倍..

还有一个不太明显的优化是 进行状态合并的时候 如果没有合成 也就是不到k个字符的合成 左边合成和右边合成其实都是等效的 所以我们可以省掉右边的合并钦定左边进行合并即可。

那么就是 我们只在乎右边合成了1或者0 至于更多的可以不管交给左边去合成即可。这样复杂度降为n^3*2^k/8 可以calc一下 发现可以过了.

这样对于左边的状态我们还是可以利用(n-1)%(k-1)这个东西来剪枝。

那么这道题也就做完了 我看了一眼书才发现的解法 我也没想到第二个优化 可能脑子有点乱..以后dp的时候要清醒 别看书或看题解..这点小优化还是可以想出来的我觉得。

 一直wa 发现是合并的时候 没有判断准确合并的大小和长度 不是随便合并的 0000和1可以合并但是状态得自己看 有的时候0 可能代表着0000什么的我忽略了这一点。

当然 得开long long 题目描述不清楚 当然全部开long long会T (我真不容易写一道题。注意不要全开long long 常数是int的两倍 于是把for里的改成int就过了。

//#include
#include
#include
#include
#include
#include<string>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include<set>
#include
#include
#define INF 1000000000
#define ll long long
#define R register
#define db double
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int MAXN=301,maxn=8;
ll n,k,ans;
int a[MAXN],p[1<<maxn];
int s[1<<maxn];
ll f[MAXN][MAXN][1<<maxn];
//f[i][j][k] 表示由区间i到区间j合成后状态为k的最大值
signed main()
{
    //freopen("1.in","r",stdin);
    n=read();k=read();
    memset(f,0xcf,sizeof(f));
    for(int i=1;i<=n;++i)a[i]=read(),f[i][i][a[i]]=0;
    for(int i=0;i<(1<i)
        s[i]=read(),p[i]=read();
    for(int len=2;len<=n;++len)
    {
        for(int i=1;i<=n-len+1;++i)
        {
            int j=i+len-1;
            for(int l=i;ll)
            {
                int len2=j-l;
                if((len2-1)%(k-1))continue;
                int len1=l-i+1;
                len1=(len1-1)%(k-1)+1;
                for(int s1=0;s1<(1<s1)
                {
                    if(f[i][l][s1]<0)continue;
                    if(f[l+1][j][0]>=0)
                    {
                        int state=s1<<1;
                        if(len1==k-1)
                            f[i][j][s[state]]=max(f[i][j][s[state]],f[i][l][s1]+f[l+1][j][0]+p[state]);
                        else
                            f[i][j][state]=max(f[i][j][state],f[i][l][s1]+f[l+1][j][0]);
                    }
                    if(f[l+1][j][1]>=0)
                    {
                        int state=s1<<1|1;
                        if(len1==k-1)
                            f[i][j][s[state]]=max(f[i][j][s[state]],f[i][l][s1]+f[l+1][j][1]+p[state]);
                        else
                            f[i][j][state]=max(f[i][j][state],f[i][l][s1]+f[l+1][j][1]);
                    }
                }
            }
        }
    }
    for(int i=0;i<(1<<(k-1));++i)
        ans=max(ans,f[1][n][i]);
    printf("%lld\n",ans);
    return 0;
}
View Code

 LINK:分数规划生成树

其实就是想让我们找出一个最小的生成树罢了,直接prim会比克鲁斯卡尔快一点。注意这里需要二分一下比值因为我们不好直接求出这个比值。
所以考虑先二分,然后权值就有了我们想办法让mid减小的那个方式生成树即可。

//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include<string>
#include
#include
#include
#include
#include
#include<set>
#include
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define db double
#define EPS 1e-4
#define mp make_pair
#define F first
#define S second
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=1010;
int n;
struct wy
{
    int x,y,z;
}t[MAXN];
int vis[MAXN];
db a[MAXN][MAXN],d[MAXN];
priority_queueint> > q;
inline int abs(int x){return x<0?-x:x;}
inline db dis(int x,int y)
{
    return sqrt(1.0*(t[x].x-t[y].x)*(t[x].x-t[y].x)+1.0*(t[x].y-t[y].y)*(t[x].y-t[y].y));
}
inline int check(db w)
{
    db ans=0;
    for(int i=1;i<=n;++i)d[i]=INF*1.0,vis[i]=0;
    q.push(mp(0,1));
    while(q.size())
    {
        int x=q.top().S;
        if(vis[x])
        {
            q.pop();
            continue;
        }
        ans=ans-q.top().F;
        vis[x]=1;
        for(int i=1;i<=n;++i)
        {
            if(vis[i])continue;
            db dd=abs(t[x].z-t[i].z)-a[x][i]*w;
            if(d[i]>dd)
            {
                d[i]=dd;
                q.push(mp(-d[i],i));
            }
        }
    }
    if(ans<=0)return 1;
    return 0;
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();
    for(int i=1;i<=n;++i)
    {
        int x,y,z;
        x=read();y=read();z=read();
        t[i]=(wy){x,y,z};
    }
    for(int i=1;i<=n;++i)
        for(int j=i+1;j<=n;++j)
            a[i][j]=a[j][i]=dis(i,j);
    db l=0,r=100;
    while(l+EPS<r)
    {
        db mid=(l+r)/2;
        if(check(mid))r=mid;
        else l=mid;
    }
    printf("%.3lf",l);
    return 0;
}
View Code

 LINK:pigs有点神奇的题目 看起来很复杂 但其实我还真不会 我有一个做法是拆点然后对于每个人都做一次最大流 但是还是无法实现猪交换的时候的合法性。

做法比较强大 是这样的我们很难完成在存在牛的点的情况下实现牛之间的交换因为考虑这个顺序比较难以控制 可能较早的点会用较晚的点的边所以这很不好写,我们不妨不建牛点 把牛放到一块然后表示牛可以任意互换,这样就不会出现上述情况了。综上我们 每次都将一堆牛直接连向一个人 如果下次还有人连相同的牛的话就把上次连的人连向当前这个人即可。

//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include<string>
#include
#include
#include
#include
#include
#include<set>
#include
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define db double
#define mp make_pair
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=1010;
int n,m,S,T,ans,len=1,t,h;
int a[MAXN],b[MAXN];
int lin[MAXN],nex[MAXN*100<<1],ver[MAXN*100<<1],e[MAXN*100<<1];
int q[MAXN],vis[MAXN],cur[MAXN];
inline void add(int x,int y,int z)
{
    ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;
    ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;
}
inline int bfs()
{
    h=t=0;
    for(int i=1;i<=T;++i)vis[i]=0,cur[i]=lin[i];
    q[++t]=S;vis[S]=1;
    while(h++<t)
    {
        int x=q[h];
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(!e[i]||vis[tn])continue;
            vis[tn]=vis[x]+1;
            q[++t]=tn;
            if(tn==T)return 1;
        }
    }
    return 0;
}
inline int dinic(int x,int flow)
{
    if(x==T)return flow;
    int rest=flow,k;
    for(int i=cur[x];i&&rest;i=nex[i])
    {
        int tn=ver[i];
        cur[x]=i;
        if(vis[tn]==vis[x]+1&&e[i])
        {
            k=dinic(tn,min(flow,e[i]));
            if(!k){vis[tn]=0;continue;}
            e[i]-=k;e[i^1]+=k;rest-=k;
        }
    }
    return flow-rest;
}
int main()
{
    //freopen("1.in","r",stdin);
    m=read();n=read();
    S=n+1;T=S+1;
    for(int i=1;i<=m;++i)a[i]=read();
    for(int i=1;i<=n;++i)
    {
        int x=read(),cnt=0;
        for(int j=1;j<=x;++j)
        {
            int y=read();
            if(b[y])add(b[y],i,INF);
            else cnt+=a[y];
            b[y]=i;
        }
        x=read();
        add(S,i,cnt);
        add(i,T,x);
    }
    int flow=0;
    while(bfs())while((flow=dinic(S,INF)))ans+=flow;
    printf("%d\n",ans);
    return 0;
}
View Code

 LINK:足球积分 看起来是个贪心。其实应该就是贪心了。很简单对于求最大值我们能赢就赢不要平局因为赢得话比平局得分高 。

输的话刚好相反 分类讨论一下即可。想了一下求最小值还真的有很大的难度 思考良久发现把所有情况搞出来取最小值即可。

很不错的贪心 虽然wa了很多次 下次在提交之前应该手玩一些数据才对。细节 有点ex 不过剩下的就没什么了。

//#include
#include
#include
#include
#include
#include<string>
#include
#include
#include
#include
#include
#include
#include
#include<set>
#include
#include
#include
#include
#include
#define INF 1000000010
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define mp make_pair
#define ll long long
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
    ll x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const ll MAXN=100010,maxn=MAXN<<1;
ll x,y,n;
ll ans,ans1;
signed main()
{
    //freopen("1.in","r",stdin);
    while(scanf("%d%d%d",&x,&y,&n)==3)
    {
        ans=ans1=0;
        ll xx=x,yy=y,nn=n;
        if(n==1)
        {
            if(x>y)ans=ans1=3;
            if(x==y)ans=ans1=1;
            printf("%lld %lld\n",ans,ans1);
            continue;
        }
        //先求最大值
        ll w=n-1;
        ll v=min(w,x);
        ans+=v*3;
        w-=v;
        x-=v;
        if(x>y)ans+=3;
        if(x==y)++ans;
        ans+=w;
        printf("%lld ",ans);
        //再求最小值
        if(xx>yy)
        {
            ans1+=3;
            --nn;
            v=min(yy,nn);
            nn-=v;
            ans1+=nn;
            printf("%lld\n",ans1);
            continue;
        }
        --nn;
        if(xx==yy)
        {
            if(nn>=3&&yy>=3)
            {
                ans1+=3;
                v=min(yy,nn);
                nn-=v;
                ans1+=nn;
                printf("%lld\n",ans1);
            }
            else
            {
                ++ans1;
                ans1+=nn;
                printf("%lld\n",ans1);
            }
        }
        else//对于 xx
        {
            ll w1=3,w2=1,w3=0;
            w1=w1+(nn-min(nn,yy));
            yy-=xx;
            w2=w2+(nn-min(nn,yy));
            --yy;
            w3=w3+(nn-min(nn,yy));
            ans1=min(w1,w2);
            ans1=min(ans1,w3);
            printf("%lld\n",ans1);
        }
    }
    //cout<
    return 0;
}
View Code

 LINK:背包的方案数问题。  求不适用第一个物品且装满背包的方案数 再求不用第二个物品的方案数 一直求到第n个?

一个比较显然的思路是暴力 n^2m的暴力 考虑优化这个过程。考虑 我们每次把有用的东西保存下来。也就是说 我们先对整体进行一次01背包方案数 然后 想办法求出第一个除去第一个物品的方案数 观察 把dp式加法换成减法即可。考虑一下实际的意义。

我们先广义的分析:做背包 和 物品的顺序无关 所以我们可以想象成第一个物品是最后一个加进去的 所以可以看出 这样的做法显然正确。

狭义的想:这很显然。

当时我写的无脑暴力 还是保存一下吧 。

#include
#include
#include
#include
#include<string>
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int maxn=1014;
int n,m;
int w[maxn],f[10007],ans=0;
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;i++)w[i]=read(),ans+=w[i];
    f[0]=1;
    for(int k=1;k<=n;k++)
    {
        memset(f,0,sizeof(f));
        f[0]=1;
        for(int i=1;i<=n;i++)
        {    
            if(ans-w[i]break;
            for(int j=m;j>=w[i];j--)
            {    
                    if(i==k)continue;
                    f[j]=(f[j]%maxn+f[j-w[i]]%maxn)%maxn;
            }
        }
        printf("%d ",f[m]%maxn);
        if(k==n)printf("\n");
    }
    return 0;
}
View Code

这是 很顺利的 倒序背包清空一下即可。

//#include
#include
#include
#include
#include
#include<string>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include<set>
#include
#include
#define INF 1000000010
#define ll long long
#define mp(x,y) make_pair(x,y)
#define un unsigned
#define db double
#define EPS 1e-5
#define mod 1014
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}

const int MAXN=10010;
int n,m;
int a[MAXN],f[MAXN],w[MAXN];
int main()
{
    //freopen("FILE.in","r",stdin);
    //freopen("FILE.out","w",stdout);
    n=read();m=read();
    f[0]=1;
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=n;++i)
        for(int j=m;j>=a[i];--j)
            f[j]=(f[j]+f[j-a[i]])%mod;
    //for(int i=1;i<=m;++i)cout<
    for(int i=1;i<=n;++i)
    {
        if(m"%d\n",f[m]);continue;}
        for(int j=0;j<=m;++j)w[j]=f[j];
        for(int j=a[i];j<=m;++j)f[j]=(f[j]-f[j-a[i]])%mod;
        printf("%d ",((f[m]+mod)%mod));
        for(int j=0;j<=m;++j)f[j]=w[j];
    }
    return 0;
}
View Code

 LINK:最大速度 中级搜索。 这题 搜索起来比较麻烦。

由于到达每个点还有方向考虑把方向也存起来 考虑dij 开跑 但是连续转两次也算掉头 所以还不免记录上次左转还是右转。

注意 大根堆别写错 方向别搞错 预处理要仔细 dij 换成spfa 我们发现 有状态都是0 但是一个0状态能更新一个0状态 所以只能spfa了..

//#include
#include
#include
#include
#include
#include<string>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include<set>
#include
#include
#define INF 1000000010
#define ll long long
#define mp(x,y) make_pair(x,y)
#define un unsigned
#define db double
#define EPS 1e-5
#define mod 1014
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int MAXN=31;
int st,en,op,s1,s2,vv,n,m,cnt,ans;
int dx[5]={0,1,-1,0,0};
int dy[5]={0,0,0,1,-1};
int f[MAXN][MAXN][5],fa[MAXN*MAXN];
int vis[MAXN][MAXN][5],id[MAXN][MAXN];
int d[5][5][2],v[5][5],g[5][5];
struct wy
{
    int x,y,op;
    int v,pre;
    int friend operator <(wy a,wy b)
    {
        return a.v<b.v;
    }
};
char a[MAXN][MAXN];
priority_queue q;
inline int getfather(int x){return x==fa[x]?x:fa[x]=getfather(fa[x]);}
inline void bfs()
{
    while(q.size())
    {
        wy s=q.top();q.pop();
        //if(vis[s.x][s.y][s.op])continue;
        //vis[s.x][s.y][s.op]=1;
        for(int i=1;i<=4;++i)
            {
                int xx=s.x+d[s.op][i][0];
                int yy=s.y+d[s.op][i][1];
                if(xx<1||yy<1||xx>n||yy>m)continue;
                if(a[xx][yy]=='.')continue;
                int w=max(0,s.v+v[s.op][i]);
                if(g[s.op][i]==s.pre&&s.pre>0)w=0;
                if(f[xx][yy][i]<w)
                {
                    f[xx][yy][i]=w;
                    q.push((wy){xx,yy,i,w,g[s.op][i]});
                }
            }
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();vv=read();
    memset(f,0xcf,sizeof(f));
    for(int i=1;i<=n;++i)
    {
        scanf("%s",a[i]+1);
        for(int j=1;j<=m;++j)
        {
            id[i][j]=++cnt;fa[cnt]=cnt;
            if(a[i][j]!='.'&&a[i][j]!='#'&&a[i][j]!='F')
            {
                if(a[i][j]=='E')op=1;
                if(a[i][j]=='W')op=2;
                if(a[i][j]=='N')op=3;
                if(a[i][j]=='S')op=4;
                st=i,en=j;
            }
            if(a[i][j]=='F')s1=i,s2=j;
        }
    }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
        {
            if(a[i][j]=='.')continue;
            for(int k=1;k<=4;++k)
            {
                int x=i+dx[k];
                int y=j+dy[k];
                if(x<1||y<1||x>n||y>m)continue;
                if(a[x][y]=='.')continue;
                int xx=getfather(id[x][y]);
                int yy=getfather(id[i][j]);
                fa[xx]=yy;
            }
        }
    if(getfather(fa[id[st][en]])!=getfather(fa[id[s1][s2]]))
    {
        puts("-1");return 0;
    }
    f[st][en][op]=vv;
    d[1][1][0]=0;d[1][1][1]=1;v[1][1]=1;g[1][1]=0;
    d[1][2][0]=0;d[1][2][1]=0;v[1][2]=-INF;g[1][2]=-1;
    d[1][3][0]=0;d[1][3][1]=0;v[1][3]=-35;g[1][3]=1;//向左
    d[1][4][0]=0;d[1][4][1]=0;v[1][4]=-40;g[1][4]=2;//向右
    
    d[2][1][0]=0;d[2][1][1]=0;v[2][1]=-INF;g[2][1]=-1;
    d[2][2][0]=0;d[2][2][1]=-1;v[2][2]=1;g[2][2]=0;
    d[2][3][0]=0;d[2][3][1]=0;v[2][3]=-40;g[2][3]=2;
    d[2][4][0]=0;d[2][4][1]=0;v[2][4]=-35;g[2][4]=1;
    
    d[3][1][0]=0;d[3][1][1]=0;v[3][1]=-40;g[3][1]=2;
    d[3][2][0]=0;d[3][2][1]=0;v[3][2]=-35;g[3][2]=1;
    d[3][3][0]=-1;d[3][3][1]=0;v[3][3]=1;g[3][3]=0;
    d[3][4][0]=0;d[3][4][1]=0;v[3][4]=-INF;g[3][4]=-1;
    
    d[4][1][0]=0;d[4][1][1]=0;v[4][1]=-35;g[4][1]=1;
    d[4][2][0]=0;d[4][2][1]=0;v[4][2]=-40;g[4][2]=2;
    d[4][3][0]=0;d[4][3][1]=0;v[4][3]=-INF;g[4][3]=-1;
    d[4][4][0]=1;d[4][4][1]=0;v[4][4]=1;g[4][4]=0;
    q.push((wy){st,en,op,vv,-2});
    bfs();
    for(int i=1;i<=4;++i)ans=max(ans,f[s1][s2][i]);
    printf("%d\n",ans);
    return 0;
}
View Code

 

你可能感兴趣的:(jzyz 题库 题目选做)