2020-9-18 大二2020下训练一

Powered by:AB_IN 局外人

A 青蛙赶路

d p [ i ] [ 0 ] dp[i][0] dp[i][0]代表上一步是走而到位置 i i i的方案数总数。

d p [ i ] [ 1 ] dp[i][1] dp[i][1]代表上一步是跳而到位置 i i i的方案数总数。
所以转移方程

  • d p [ i ] [ 0 ] = ( d p [ i − 1 ] [ 0 ] + d p [ i − 1 ] [ 1 ] ) dp[i][0]=(dp[i-1][0]+dp[i-1][1])%mod; dp[i][0]=(dp[i1][0]+dp[i1][1])
  • d p [ i ] [ 1 ] = ( d p [ i − m ] [ 0 ] ) dp[i][1]=(dp[i-m][0])%mod; dp[i][1]=(dp[im][0])
    只能是走到 i − m i-m im位置的跳过来的。
#include <bits/stdc++.h>
#define ll long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e5+10;
using namespace std;
const int mod=1000000007;
ll dp[N][2],sum[N],l,r,n,m;
namespace IO{
    
    
    char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
    char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
    inline char gc(){
    
    
        if(ip!=ip_)return *ip++;
        ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
        return ip==ip_?EOF:*ip++;
    }
    inline void pc(char c){
    
    
        if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
        *op++=c;
    }
    inline ll read(){
    
    
        register ll x=0,ch=gc(),w=1;
        for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
        for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
        return w*x;
    }
    template<class I>
    inline void write(I x){
    
    
        if(x<0)pc('-'),x=-x;
        if(x>9)write(x/10);pc(x%10+'0');
    }
    class flusher_{
    
    
    public:
        ~flusher_(){
    
    if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
    }IO_flusher;
}
using namespace IO;
int main()
{
    
    
    n=read();m=read();
    for(int i=0;i<m;i++){
    
    //m之前的只能走着到达,所以都是1
        dp[i][0]=1;
    }
    for(int i=m;i<=N;i++){
    
    
        dp[i][0]=(dp[i-1][0]+dp[i-1][1])%mod;
        dp[i][1]=(dp[i-m][0])%mod;
    }
    for(int i=1;i<=N;i++){
    
    
        sum[i]=(sum[i-1]+dp[i][0]+dp[i][1])%mod;
    }
    for(int i=1;i<=n;i++){
    
    
        l=read();r=read();
        write((ll)(sum[r]-sum[l-1]+mod)%mod);
        pc('\n');
    }
    return 0;
}

B 贪吃蛇大作战

d p dp dp线段树优化。
从二维问题转变为一维问题。

  • 先把 y y y的坐标离散化,再写个 c m p cmp cmp(先按照 x x x升序,再按照 y y y升序)。从下往上 d p dp dp即可。
  • 利用线段树求区间最大值(这里注意真正的进入线段树的下标不是 i i i,而是 b [ i ] . y b[i].y b[i].y)。更新每个点的最大值即为,这一行及这一行以下的最大值+这一点的权值,最后 1 1 1 n n n求区间最大值即可。
  • 代码最后有一组数据,很多题解都过不了,算是 h a c k hack hack了。
#include <bits/stdc++.h>
#define ll long long
#define rep(i,x,y) for (ll i=(x);i<=(y);i++)
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ls i<<1
#define rs i<<1|1

using namespace std;
const int N=1e6+10;
struct sa
{
    
    
    ll x;
    ll y;
    ll w;
}b[N<<2];
ll a[N<<2],tr[N<<2];
ll n,m,x,y,k;

inline void pushup(ll i)
{
    
    
    tr[i] = max(tr[ls],tr[rs]);
}
inline void bulid(ll i,ll l,ll r)
{
    
    
    if(l==r){
    
    
        tr[i]=0;
        return;
    }
    ll mid=(l+r)>>1;
    bulid(ls,l,mid);
    bulid(rs,mid+1,r);
    pushup(i);
}

inline void update(ll i,ll l,ll r,ll x,ll k)
{
    
    
    if(l>x||r<x) return;
    if(l==x&&l==r){
    
    
        tr[i]=k;
        return;
    }
    ll mid=(l+r)>>1;
    update(ls,l,mid,x,k);
    update(rs,mid+1,r,x,k);
    pushup(i);
}

ll query(ll i,ll l,ll r,ll x,ll y)
{
    
    
    ll res=-1;
    if(l>y||r<x) return 0;
    if(l>=x&&r<=y) return tr[i];
    ll mid=(l+r)>>1;
    if(x<=mid) res=max(res,query(ls,l,mid,x,y));
    if(y>mid)  res=max(res,query(rs,mid+1,r,x,y));
    return res;
}

bool cmp(const sa &a, const sa &b) {
    
    
    if (a.x != b.x) return a.x<b.x;
    else return a.y<b.y;
}

int t;
int main()
{
    
    
    IOS;
    cin>>t;
    while(t--){
    
    
        cin>>n;
        rep(i,1,n){
    
    
            cin>>b[i].x>>b[i].y>>b[i].w;
            a[i]=b[i].y;
        }
        sort(a+1,a+1+n);
        ll m=unique(a+1,a+1+n)-a-1;
        rep(i,1,n){
    
    
            b[i].y=lower_bound(a+1,a+1+m,b[i].y)-a;
        }
        sort(b+1,b+1+n,cmp);
        ///b[i].y才是真正的下标
        bulid(1,1,n);
        rep(i,1,n){
    
    
            ll q=query(1,1,n,0,b[i].y);
            update(1,1,n, b[i].y, q+b[i].w);
        }
        cout<<query(1,1,n,1,n)<<endl;
    }
    return 0;
}
/*
2
5
1 2 3
1 3 4
2 2 1
2 3 5
1 6 1
*/

C 小L的数列

  • 先看一下数列的总和是不是 0 0 0
  • 从头开始找 2 ∗ s u m 3 \frac {2*sum} {3} 32sum的点(不能为 1 1 1 n n n),用前缀和维护一下。
  • 再从头开始找 s u m 3 \frac {sum} {3} 3sum(不能为 n n n), a n s ans ans加上从这个点(不包括这个点)以后的 2 ∗ s u m 3 \frac {2*sum} {3} 32sum点的个数即可。
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define rint register int
#define ll long long
using namespace std;
const int N=1e6+10;
ll n,ans,a[N],b[N],sum;
int main()
{
    
    
    IOS;
    while(cin>>n)
    {
    
    
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        ans=0;
        sum=0;
        for(rint i=1;i<=n;i++){
    
    
            cin>>a[i];
            sum+=a[i];
        }
        if(sum%3!=0){
    
    
            printf("0\n");
            continue;
        }
        ll tot=0;
        for(rint i=1;i<=n;i++){
    
    
            tot+=a[i];
            if(tot==sum*2/3&&i!=1&&i!=n){
    
    
                b[i]++;
            }
            b[i]+=b[i-1];
        }
        tot=0;
        for(rint i=1;i<=n;i++){
    
    
            tot+=a[i];
            if(tot==sum/3&&i!=n)
                ans+=b[n]-b[i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

D 魔法王国

最小生成树。

#include <bits/stdc++.h>
#define ll long long
#define rep(i,x,y) for (ll i=(x);i<=(y);i++)

using namespace std;
const int maxn=1e6+10;
ll n,m,u,v,w,ans,cnt;

ll fa[maxn];

struct sa{
    
    
    ll u,v,w;
}e[maxn];

bool cmp(struct sa x,struct sa y){
    
    
    return x.w<y.w;
}

ll find(ll x) {
    
    
    if(fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}
ll t,vis[maxn];
int main()
{
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--){
    
    
        ans=0;
        cnt=0;
        memset(e, 0, sizeof(e));
        cin>>n>>m;
        rep(i,1,m) cin>>e[i].u>>e[i].v>>e[i].w;
        sort(e+1,e+1+m,cmp);
        rep(i,1,n) fa[i]=i;
        rep(i,1,m){
    
    
            if(cnt==n-1) break;
            w=e[i].w; u=find(e[i].u);v=find(e[i].v);
            if(u!=v){
    
    
                fa[u]=v;
                if(i==1) ans+=w;
                if(vis[w]) ans+=1;
                if(w>ans) ans=w;
                cnt++;
                vis[w]=1;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45859188/article/details/108684579