3.14杂题选讲

强烈谴责这次的出题人把难度搞这么高,让我这个菜鸡怎么活……


T1

非常显然的思路是01分数规划,然后就不会做了(大雾

考虑\(a\)小的可以连接到\(a\)大的任务上一起做,那么显然也可以把任务按\(a\)排序后相同的放在一起分组。

然后就可以开心快乐地DP了。

\(dp_{i,j}\)表示前\(i\)组里有\(j\)个记入答案,所能得到的最小权值(权值就是01分数规划搞出来的东西)。

于是有转移方程:
\[ dp_{i,j}=\max\{dp_{i-1,j-k}+W_{i,k}\} \]
其中\(W_{i,k}\)表示第\(i\)组里权值最小的\(k\)个的权值之和,随便处理一下就好了。

注意一个状态要合法需要满足一些条件,可以自己推一下。

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define templ template<typename T>
    #define sz 100
    typedef long long ll;
    typedef long double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
    templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
    templ inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    char sr[1<<21],z[20];int C=-1,Z=0;
    inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    inline void print(register int x)
    {
        if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]='\n';
    }
    void file()
    {
        #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        #endif
    }
    inline void chktime()
    {
        #ifndef ONLINE_JUDGE
        cout<<(clock()-t)/1000.0<<'\n';
        #endif
    }
    #ifdef mod
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
    ll inv(ll x){return ksm(x,mod-2);}
    #else
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
    #endif
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

int n;
struct hh{ll a,b;inline bool operator < (const hh &y) const {return a>y.a;}}a[sz];

vector<db>w[sz],sum[sz];
int c[sz];
db dp[sz][sz]; // Ç°i×飬ÓÐj¸öÓÐЧµÄ£¬µÃµ½µÄ×î´óȨֵ 
// j*2 \geq c[i]

bool judge(db W)
{
    int cnt=0;
    rep(i,1,n) w[i].resize(0),sum[i].resize(0);
    rep(i,1,n) 
    {
        if (i==1||a[i].a!=a[i-1].a) ++cnt;
        w[cnt].push_back(a[i].a-W*a[i].b);
    }
    rep(i,1,cnt)
    {
        sort(w[i].begin(),w[i].end());
        sum[i].resize(w[i].size());
        sum[i][0]=w[i][0];
        c[i]=c[i-1]+w[i].size();
        rep(j,1,(int)sum[i].size()-1) sum[i][j]=sum[i][j-1]+w[i][j];
    }
    rep(i,0,n) rep(j,0,c[cnt]) dp[i][j]=1e19;
    dp[0][0]=0;
    rep(i,1,cnt) 
        rep(j,1,c[i]) 
            if (j*2>=c[i])
            {
                dp[i][j]=dp[i-1][j];
                rep(k,1,min(j,c[i]-c[i-1])) if (c[i]-c[i-1]-k<=j*2-c[i-1]-2*k)
                    chkmin(dp[i][j],dp[i-1][j-k]+sum[i][k-1]);
            }
                
    db ret=1e19;
    rep(i,1,n) chkmin(ret,dp[cnt][i]);
    return ret<=0;
}

int main()
{
    file();
    read(n);
    rep(i,1,n) read(a[i].a);
    rep(i,1,n) read(a[i].b);
    sort(a+1,a+n+1);
    db l=0,r=1e10;
    while (r-l>=1e-7)
    {
        db mid=(l+r)/2;
        if (judge(mid)) r=mid;
        else l=mid;
    }
    printf("%lld",(ll)ceil(l*1000));
    return 0;
}

T2

第一问非常无趣,\(a_i=a_i-i\)后求一个\(a\)的最长不下降子序列就好了。

\(dp_i\)表示以\(i\)结尾的最长不降子序列长度。

第二问考虑DP,设\(f_i\)表示\(i\)不变,前\(i\)个都已经变为不降序列的最小代价。

\(f_i\)可以由\(f_j\)转移而来,其中\(j<i\;\;\&\&\;\;dp_j=dp_i-1\)

注意到一个性质:这段区间中的\(k\)都满足\(a_j>a_k \; \; or \;\; a_k>a_i\)

所以可以感受一下,\(j\rightarrow i\)之间的\(a\)必然会变成这样:一段都等于\(a_j\),后一段等于\(a_i\)。如果不是这样也可以调整成这样。

然后暴力枚举分界点即可。

复杂度似乎很大,但数据随机,也就这么跑过去了。

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define templ template<typename T>
    #define sz 50500 
    typedef long long ll;
    typedef double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
    templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
    templ inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    char sr[1<<21],z[20];int C=-1,Z=0;
    inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    inline void print(register int x)
    {
        if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]='\n';
    }
    void file()
    {
        #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        #endif
    }
    inline void chktime()
    {
        #ifndef ONLINE_JUDGE
        cout<<(clock()-t)/1000.0<<'\n';
        #endif
    }
    #ifdef mod
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
    ll inv(ll x){return ksm(x,mod-2);}
    #else
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
    #endif
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

int n;
int a[sz];

int dp[sz];
int mn[sz],top;

ll f[sz];
vector<int>v[sz];

int main()
{
    file();
    read(n);
    rep(i,1,n) read(a[i]),a[i]-=i;
    mn[0]=-1e9;
    a[n+1]=1e9;
    rep(i,1,n+1)
    {
        int pos=upper_bound(mn,mn+top+1,a[i])-mn-1;
        dp[i]=pos+1;
        if (pos==top) ++top,mn[top]=1e9;
        chkmin(mn[pos+1],a[i]);
    }
    printf("%d\n",n-dp[n+1]+1);
    rep(i,1,n+1) v[dp[i]].push_back(i);
    v[0].push_back(0);
    rep(i,1,n+1) f[i]=1e18;
    a[0]=-1e9;f[0]=0;
    rep(i,1,n+1)
    {
        for (int x:v[dp[i]-1]) if (a[x]<=a[i]&&x<i)
        {
            ll sum1=0,sum2=0;
            rep(j,x+1,i-1) sum2+=abs(a[j]-a[i]);
            ll cur=sum2;
            rep(j,x+1,i-1) sum1+=abs(a[j]-a[x]),sum2-=abs(a[j]-a[i]),chkmin(cur,sum1+sum2);
            chkmin(f[i],f[x]+cur);
        }
    }
    cout<<f[n+1];
    return 0;
}

T3

这题没做出来,我的脑子呢……

直接给邻接矩阵做矩阵乘法,相当于是DP。

由于食人鱼的周期特别短,取\(12\)为一周期,把每一个时刻的邻接矩阵处理出来,然后瞎乘一通就好了。

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define templ template<typename T>
    #define sz 55 
    #define mod 10000
    typedef long long ll;
    typedef double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
    templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
    templ inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    char sr[1<<21],z[20];int C=-1,Z=0;
    inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    inline void print(register int x)
    {
        if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]='\n';
    }
    void file()
    {
        #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        #endif
    }
    inline void chktime()
    {
        #ifndef ONLINE_JUDGE
        cout<<(clock()-t)/1000.0<<'\n';
        #endif
    }
    #ifdef mod
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
    ll inv(ll x){return ksm(x,mod-2);}
    #else
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
    #endif
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

int n,m;
ll K;
int F,T;

struct Matrix
{
    ll a[sz][sz];
    Matrix(){rep(i,1,n) rep(j,1,n) a[i][j]=0;}
    void init(){rep(i,1,n) a[i][i]=1;}
};
inline Matrix operator * (const Matrix &a,const Matrix &b)
{
    Matrix ret;
    rep(i,1,n) rep(k,1,n) rep(j,1,n) (ret.a[i][j]+=a.a[i][k]*b.a[k][j]%mod)%=mod;
    return ret;
}

Matrix a,s[13],S;
void ksm(ll y)
{
    Matrix ret;ret.init();
    for (;y;y>>=1,S=S*S) if (y&1) ret=ret*S;
    S=ret;
}

int p[5];

int main()
{
    file();
    read(n,m,F,T,K);++F,++T;
    int x,y;
    rep(i,1,m) read(x,y),++x,++y,a.a[x][y]++,a.a[y][x]++;
    rep(i,1,12) s[i]=a;
    read(m);
    while (m--)
    {
        read(x);
        rep(i,0,x-1) read(p[i]),++p[i];
        rep(i,1,12) 
        {
            y=p[i%x];
            rep(j,1,n) s[i].a[j][y]=0;
        }
    }
    S.init();
    rep(i,1,12) S=S*s[i];
    ksm(K/12);
    rep(i,1,K%12) S=S*s[i];
    cout<<S.a[F][T];
    return 0;
}

T4

事情开始变得恶心起来。

这题我会专门写一篇博客的,等下放上来。


T5

暂时还不会,以后搞。

猜你喜欢

转载自www.cnblogs.com/p-b-p-b/p/10542156.html