杂乱的题

小A和uim之大逃离 II
这个问题就是一个裸的bfs,多了一个专移的方向而已,很简单

#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
int n , m , xx[5] = { 1 , -1 , 0 , 0 }, yy[5] = { 0, 0 , 1 , -1 }, vis[1999][1999][2];
char a[1999][1999] ;
struct st{
    int x ,y ,s ,f ;
};
queue < st > q ;
int bfs()
{
    st o;
    o.x = 1 , o.y = 1, o.s = 0 ,o.f = 0 ;
    st o2;
    o2.x = 1 , o2.y = 1, o2.s = 0 ,o2.f = 1 ;
    vis[1][1][0] = 1;vis[1][1][1] = 1;
    q.push (o) ;
    q.push (o2);
    while(!q.empty ()){
        st w = q.front ();q.pop ();
        //printf("%d %d %d %d\n",w.x,w.y,w.s,w.f);
        for(int i = 0 ; i <= 4 ; i++){
            if(i == 4 && w.f) continue;
            st tmp;
            tmp.x = w.x + xx[i];
            tmp.y = w.y + yy[i];
            tmp.s = w.s + 1;
            if(i == 4) tmp.f = 1;
            else tmp.f = w.f;
            if(tmp.x>n||tmp.x<1||tmp.y<1||tmp.y>m) continue ;

            if(a[tmp.x][tmp.y] == '.'){
                if(!vis[tmp.x][tmp.y][tmp.f]){
                    vis[tmp.x][tmp.y][tmp.f] = 1;
                    if(tmp.x == n && tmp.y == m) {
                    printf("%d",tmp.s); return 1;
            }
                    //printf("%d %d %d %d\n",tmp.x,tmp.y,tmp.s,tmp.f);
                    q.push(tmp);
                }
            }
        }
    }
    return 0;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&xx[4],&yy[4]);
    for(int i=1;i<=n;i++)
     for(int j=1;j<=m;j++)
      cin >> a[i][j];

    if(!bfs()) printf("-1");
    return 0;
}

松江1843路
这个题就是一个模拟题
因为最两面的无论在哪一定要走
所以可以用较小的人数抵消,最后的位置就是最优的位置

#include<cstdio>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
ll n,l,x[199999],r[199999],ans; 
int main()
{
    scanf("%lld%lld",&l,&n);
    for(ll i=1;i<=n;i++){
        scanf("%lld%lld",&x[i],&r[i]);
    }
    ll h=1,t=n;
    while(t>h){
        ll w=min(r[t],r[h]);
        r[t]-=w;
        r[h]-=w;
        ans+=w*(x[t]-x[h]);
        if(!r[t])t--;
        if(!r[h])h++;
    }
    printf("%lld",ans);
}

小A的糖果

又一道模拟题
就枚举糖果,看邻近的是否小于x,大于就吃掉,优先吃后面的,因为前面的已经优化过了。

#include<cstdio>
using namespace std;
long long n,a[199999],ans,m;
int main(){
    scanf("%lld%lld",&n,&m);
    for(long long i=1;i<=n;i++)
    scanf("%lld",&a[i]);
    for(long long i=1;i<=n;i++)
    if(a[i]+a[i+1]>m)
    {
        long long w=a[i]+a[i+1]-m;ans+=w;
        if(a[i+1]>=w) a[i+1]-=w;
        else if(a[i+1]<w) a[i]-=w-a[i+1],a[i+1]=0;    
    }
    printf("%lld",ans);
}

跑路
就是一个dp啊,题解上还扯什么倍增,吓得我都不敢做了,这题跟倍增毛线关系都没有。。。。
dp[i][j][k]表示j到k 2^i的距离能不能到,很明显
如果j到k 2^i-1的距离能到,且k到q 2^i-1的距离也能到,那么j到q 2^i也能到
那么动态转移方程就出来了
dp[i][j][q]=dp[i-1][j][k]&dp[i-1][k][q];
接下来跑最短路就行了。

#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
using namespace std;
int n,m;long long a[1999][1999];bool dp[66][66][66];
int main()
{

    scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)a[i][j]=65;
    while(m--){
        int x,y;
        scanf("%d%d",&x,&y);
        a[x][y]=1;
        dp[0][x][y]=1;
    }
    for(int i=1;i<=64;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                for(int q=1;q<=n;q++){
                if(dp[i-1][j][k]&&dp[i-1][k][q])
                dp[i][j][q]=1,a[j][q]=1;
            }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++){
                a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
            }
    printf("%lld",a[1][n]);
}

hdu 手机的生产
思路
找规律可以发现,只有表达式的话,fork()会产生3台手机,fork()fork()会产生4台手机,fork()fork()fork会产生5台手机……依次类推。
那么我们可以用|把若干个连续的块分割开,每个长度为x的块会产生x−1个结果为0的表达式,1个结果为1的表达式,那么我们可以从右边往左边递推,假设共tot个块,可以得到f[i]=[i,tot]段块产生的手机个数,容易得到DP方程:
f[i]=(num[i]−1)f[i+1]+1,num[i]=第i段连续的$的长度

#include <cstdio>
using namespace std;
char s[6];
int a[99999]={0,1},f[99999],now=1;
int mod=998244353;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%s",s);
        if(s[0]=='&') a[now]++;
        else a[++now]=1;
    }
    for(int i=now;i>=0;i--)
     f[i]=(1ll*f[i+1]*a[i+1]+1)%mod;
    printf("%d",f[0]);
}

uoj 赴京赶考
有人说:
对于(ai,bi),若ai+1≠ai,则无论bi取何值,显然(ai,bi)到(ai+1,bi)都是需要花费1单位时间的。因此我们可以在x维度和y维度分别定义两种边:若ai≠ai+1,则ai到ai+1的距离就是1,否则为0。y维度亦然。

因此我们可以将x坐标和y坐标分块处理,得到每个维度上的边权的前缀和。然后根据x维度直接从xs走到xt、x维度从xs穿越边界走到xt、y维度直接从ys走到yt、y维度从ys穿越走到yt这四种情况进行讨论,得到最终的最短距离即可。复杂度O(n+m+q)

我也不知道为什么这样,就写了。。。。。。

#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
int n,m,t;
int a[199999],b[199999],sx[199999],sy[199999];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        if(i!=1)
        sx[i]=sx[i-1]+(a[i]^a[i-1]);
    }
    for(int i=1;i<=m;i++) {
        scanf("%d",&b[i]);
        if(i!=1)
        sy[i]=sy[i-1]+(b[i]^b[i-1]);
    }
    scanf("%d",&t);
    while(t--){
        int x1,x2,y1,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        int ans;
        if(x2>=x1)
        ans=min(sx[x2]-sx[x1],sx[n]-sx[x2]+sx[x1]+(a[n]^a[1]));
        else ans=min(sx[n]-sx[x1]+sx[x2]+(a[n]^a[1]),sx[x1]-sx[x2]);
        if(y2>=y1)
        ans+=min(sy[y2]-sy[y1],sy[m]-sy[y2]+sy[y1]+(b[m]^b[1]));
        else ans+=min(sy[m]-sy[y1]+sy[y2]+(b[m]^b[1]),sy[y1]-sy[y2]);

        printf("%d\n",ans);
    }

} 

hdu 6119
小小粉丝度度熊
先把区间合并,在对他们补,找最大的连续区间

#include<cstdio>
#include<iostream>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
struct st{
    ll l,r;
}a[199999];
int n;ll m;st ra[199999];int len[199999]; 
int cmp(const st a,const st b){
    if(a.l<b.l) return 1;
     return 0;
}
int main()
{
    while(scanf("%d%lld",&n,&m)!=EOF)
    {for(int i=1;i<=n;i++)
     scanf("%lld%lld",&a[i].l,&a[i].r);
    sort(a+1,a+n+1,cmp);
    ra[1]=a[1];
    int cnt=1;
    for(int i=2;i<=n;i++)
     if(ra[cnt].r+1>=a[i].l)
      ra[cnt].r=max(ra[cnt].r,a[i].r);
     else 
      ra[++cnt]=a[i];
    for(int i=1;i<cnt;i++)
     len[i]=ra[i+1].l-ra[i].r-1;
    int l=1,now=0;
    ll ans=0;
    for(int i=1;i<cnt;i++)
    {
        now+=len[i];
        while(m<now)
         now-=len[l++];
        ans=max(ans,ra[i+1].r-ra[l].l+1+m-now);
    }
    ans=max(ans,ra[1].r-ra[1].l+1+m);
    printf("%lld\n",ans);
        }
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值