基本功练习(8月30日)

考完是懵的!!

\(prob5\):飞行路线

额,切掉之后才知道有个东西叫分层图??

就是瞎鸡儿连边,然后跑最短路就行了:

#include<iostream>
#include<cstdio>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
#define pa pair<int,int>
#define heep __gnu_pbds::priority_queue<pa,greater<pa> >
#define nm make_pair
#define int long long
const int inf=1e18;
const int xx=1e5+101;
heep q;
heep::point_iterator id[xx*10];
int dis[xx*10];
int head[xx],cnt=0,s,t,n,m,k;
struct edge{int to,val,nxt;}e[xx*10];
inline int read()
{
    int x=0;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar());
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}
inline void add(int u,int v,int w)
{
    e[++cnt]=(edge){v,w,head[u]};
    head[u]=cnt;
}
inline void dij()
{
    fur(i,0,n*(k+1)) dis[i]=inf;
    fur(i,0,k) dis[s+i*n]=0,id[s+i*n]=q.push(nm(0,s+i*n));
    while(!q.empty())
    {
        int w=q.top().second,x=w%n,z=w/n;
        q.pop();
        for(int v=head[x];v;v=e[v].nxt)
        {
            int y=e[v].to;
            if(dis[x+z*n]+e[v].val<dis[y+z*n])
            {
                dis[y+z*n]=dis[x+z*n]+e[v].val;
                if(id[y+z*n]!=0) q.modify(id[y+z*n],nm(dis[y+z*n],y+z*n));
                else id[y+z*n]=q.push(nm(dis[y+z*n],y+z*n));
            }
            if(z<k)
            {
                int i=z,j=z+1;
                if(dis[x+i*n]<dis[y+j*n])
                {
                    dis[y+j*n]=dis[x+i*n];
                    if(id[y+j*n]!=0) q.modify(id[y+j*n],nm(dis[y+j*n],y+j*n));
                    else id[y+j*n]=q.push(nm(dis[y+j*n],y+j*n));
                }
            }
        }
    }
}
signed main()
{
    n=in;m=in;k=in;
    s=in;t=in;
    fur(i,1,m)
    {
        int x=in,y=in,z=in;
        add(x,y,z);
        add(y,x,z);
    }
    dij();
    printf("%lld\n",dis[t+k*n]);
    return 0;
}

\(prob1\):米道

考完发现是二分,贼尴尬,感觉自己就是个\(sb\),都忘记中位数定理的具体内容了,无奈……

但其实可以持取,枚举左端点,右端点不断右移,可以做到\(O(n)\):

#include<iostream>
#include<cstdio>
using namespace std;
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define in read()
#define int long long
inline int read()
{
    int x=0;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar());
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}
const int xx=1e5+10;
int x[xx],xu[xx],xd[xx];
int k,n,m;
inline bool check(int i,int j)
{
    if(j>n) return false;
    int mid=(i+j)>>1;
    return (xu[mid]-xu[i]-(i-1)*(x[mid]-x[i]))+(xd[mid]-xd[j]-(n-j)*(x[j]-x[mid]))<=k;
}
signed main()
{
    n=in;m=in;k=in;
    fur(i,1,n) x[i]=in;
    fur(i,2,n) xu[i]=xu[i-1]+(i-1)*(x[i]-x[i-1]);
    fdr(i,n-1,1) xd[i]=xd[i+1]+(n-i)*(x[i+1]-x[i]);
    int ans=0,r=1;
    fur(l,1,n)
    {
        while(check(l,r)&&r<=n+1) ++r;
        ans=max(ans,r-l);
    }
    cout<<ans<<endl;
    return 0;
}

\(prob3\):缓存交换

额,傻逼贪心?

在容器里的东西肯定是挑出其中对应的下一个数最远的一个丢弃,这样肯定比丢其他的不劣,然后……题就做完了……

(可我他妈连题都没看啊!!!)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define cl(a,b) memset(a,b,sizeof(a))
#define jinitaimei signed
#define pa pair<int,int>
#define heep __gnu_pbds::priority_queue<pa>
#define nm make_pair
inline int read()
{
    int x=0;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar());
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}
const int xx=1e5+10;
int x[xx],y[xx];
int nxt[xx],nxit[xx];
bool choose[xx];
heep q;
heep::point_iterator id[xx];
jinitaimei main()
{
    int n=in,k=in;
    fur(i,1,n) y[i]=x[i]=in;
    sort(y+1,y+n+1);
    int all=unique(y+1,y+n+1)-y-1;
    fur(i,1,n) x[i]=lower_bound(y+1,y+all+1,x[i])-y;
    fur(i,0,n) nxt[i]=n+1;
    nxit[n+1]=n+1;
    fdr(i,n,1) nxit[i]=nxt[x[i]],nxt[x[i]]=i;
    int num=0,ans=0;
    fur(i,1,n)
    {
        if(choose[x[i]])
        {
            q.modify(id[x[i]],nm(nxit[i],x[i]));
            continue;
        }
        ++ans;
        if(num<k) ++num;
        else choose[q.top().second]=false,id[q.top().second]=0,q.pop();
        id[x[i]]=q.push(nm(nxit[i],x[i]));
        choose[x[i]]=true;
    }
    cout<<ans<<endl;
    return 0;
}

\(prob2\):块的计数

额,又是一道我没看的傻逼题……

一棵树根为\(i\)的树能被分成每块大小为\(T\)的充要条件是其子树有\(\frac{size_i}{T}\)\(size\)\(T\)倍数的子树,应该很容易证吧,就是加加减减一下就可以了……

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define jinitaimei signed
//#define int long long
inline int read()
{
    int x=0;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar());
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}
const int xx=1e6+10;
int sz[xx],fa[xx],cntt[xx];
vector<int>e[xx];
inline void add(int u,int v){e[u].push_back(v);}
inline void dfs(int g)
{
    sz[g]=1;
    fur(i,0,(int)e[g].size()-1)
    {
        int j=e[g][i];
        if(j==fa[g]) continue;
        fa[j]=g;
        dfs(j);
        sz[g]+=sz[j];
    }
    ++cntt[sz[g]];
}
jinitaimei main()
{
    int n=in;
    fur(i,1,n-1)
    {
        int x=in,y=in;
        add(x,y);
        add(y,x);
    }
    dfs(1);
    int ans=0;
    fur(i,1,n) if(n%i==0)
    {
        int sum=0;
        for(int j=i;j<=n;j+=i) sum+=cntt[j];
        if(sum==n/i) ++ans;
    }
    cout<<ans<<endl;
    return 0;
}

\(prob4\):动物园

看到栅栏数为\(5\)就想到状压了,可一直没想到好的转移与环的情况怎么处理,后来看了题解如茅塞顿开……

嗯……设\(f_{i,j}\)为到第\(i\)个栅栏到后\(5\)个栅栏的状态为\(j\)时能使小朋友高兴的最大方案数。

转移方程有个很好的\(f_{i,j}=max(f_{i-1,(j\&15)<<1},f_{i-1,(j\&15)<<1|1})+num_{i,j}\),而\(num_{i,j}\)为当\(i\)个栅栏状态为\(j\)能使起点为\(i\)的小朋友开心的数量。

转移需要这些代码:

fur(i,1,N)
{
    int x=in,y=in,z=in,hate=0,love=0;
    fur(j,1,y)
    {
        int q=in;q=(q-x+n)%n;
        hate|=1<<q;
    }
    fur(j,1,z)
    {
        int q=in;q=(q-x+n)%n;
        love|=1<<q;
    }
    fur(j,0,31) if((j&hate)||(~j&love)) ++num[x][j];
}  

对于环,我们可以枚举最后一个栅栏的情况,然后直接转移即可

时间复杂度\(O(2^{10}n)\):

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define cl(a,b) memset(a,b,sizeof(a))
#define jinitaimei signed
//#define int long long
inline int read()
{
    int x=0;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar());
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x;
}
const int xx=1e5+10;
int dp[xx][33];
int num[xx][33];
jinitaimei main()
{
    int n=in,N=in;
    fur(i,1,N)
    {
        int x=in,y=in,z=in,hate=0,love=0;
        fur(j,1,y)
        {
            int q=in;q=(q-x+n)%n;
            hate|=1<<q;
        }
        fur(j,1,z)
        {
            int q=in;q=(q-x+n)%n;
            love|=1<<q;
        }
        fur(j,0,31) if((j&hate)||(~j&love)) ++num[x][j];
    }
    int ans=0;
    fur(i,0,31)
    {
        cl(dp[0],0x8f);dp[0][i]=0;
        fur(j,1,n) fur(k,0,31) dp[j][k]=max(dp[j-1][(k&15)<<1],dp[j-1][(k&15)<<1|1])+num[j][k];
        ans=max(ans,dp[n][i]);
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ALANALLEN21LOVE28/p/11437823.html