2019年8月5日(NOIP模拟赛DAY1)

又爆零了!!  T_T……

prob1:同花顺(\(card\))

傻逼题竟然没写出来,郁闷……

考虑以卡牌\(i\)为同花顺的结尾,则肯定会换的卡牌数为\(num=\sum[b_j<b_i-n+1]+\sum[a_j \ne a_i \land b_j>=b_i-n+1 \land b_j<=b_i]+\sum[b_j>b_i]\).  

好吧,看到柿子就不想做了……

但其实,若用补集思想考虑一波就可以化为\(num=n-\sum[a_j=a_i \land b_j>=b_i-n+1 \land b_j<=b_i]\).

这样柿子就有好多了呢……

再已颜色为第一关键字,牌号为第二关键字进行排序,就可以做到十分优秀的循环剪枝\(break\),去除了不少的不必要操作,复杂度从\(O(n^2)\)变成了\(O\)(能过),相当优秀。

最后补一句:记得去重。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
const int xx=1e5+10;
struct prom{int c,n;}b[xx],a[xx];
inline bool cmp(prom x,prom y){return (x.c^y.c)?(x.c<y.c):(x.n<y.n);}
jinitaimei main()
{
    int n=in,cnt=0;
    fur(i,1,n) a[i]=(prom){in,in};
    sort(a+1,a+n+1,cmp);
    fur(i,1,n)
    {
        while(a[i].c==a[i+1].c&&a[i].n==a[i+1].n) ++i;
        b[++cnt]=a[i];
    }
    int ans=0;
    fur(i,1,cnt)
    {
        int tmp=0;
        fdr(j,i,1)
        {
            if(b[j].c==a[i].c&&b[j].n>=a[i].n-n+1) ++tmp;
            else break;
        }
        ans=max(ans,tmp);
    }
    printf("%lld\n",n-ans);
    return 0;
}

prob2:做实验(\(test\))

枚举数\(a\)的每个子集,询问其最后出现的时间是否在\(i-b\)\(i-1\)之间,若是,则有一点贡献,同时更新该子集的最后出现时间。

\(30\)分部分分,暴力枚举所有小于等于\(a\)的数\(i\),判断其是否是\(a\)的子集,然后进行累加贡献:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define int long long
#define jinitaimei signed
inline int read()
{
    int x=0,f=1;char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
const int xx=1e5+10;
int f[xx];
jinitaimei main()
{
    int n=in;
    fur(i,1,n)
    {
        int x=in,y=in,res=0;
        fur(j,1,x)
        {
            if((j|x)!=x) continue;
            if(f[j]<i-y) ++res;
            f[j]=i;
        }
        printf("%lld\n",res);
    }
    return 0;
}

正解 :使用按位与&枚举子集(自己推一下就好了):

#include<bits/stdc++.h>
using namespace std;
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define in read()
#define int long long
#define jinitaimei signed
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 las[xx];
jinitaimei main()
{
    int n=in;
    fur(i,1,n)
    {
        int a=in,b=in,res=0;
        for(int j=a;j;j=(j-1)&a)
        {
            if(las[j]<i-b) ++res;
            las[j]=i;
        }
        printf("%lld\n",res);
    }
    return 0;
}

貌似标码比暴力还短??

prob3:拯救世界(\(save\))

思路清晰:\(Tarjan\)缩点+\(spfa\)最长路,最后枚举终点取\(max\)即可。

(貌似\(Tarjan\)写丑了):

#include<bits/stdc++.h>
using namespace std;
#define fur(i,a,b) for(int i=a;i<=b;++i)
#define fdr(i,a,b) for(int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
#define pi pair<int,int>
#define nm make_pair
#define in read()
inline int read()
{
    int x=0,k=1;
    char ch=getchar();
    for(;!isalnum(ch);ch=getchar()) k=(ch=='-'?-1:1);
    for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
    return x*k;
}
const int xx=5e5+10;
int sta[xx],top=0,all=0;
int low[xx],id[xx],cnt=0;
int sum[xx],w[xx];
int bel[xx],bar[xx];
int u[xx],v[xx],dis[xx];
bool vis[xx],viss[xx];
vector<int>e[xx];
vector<pi>f[xx];
deque<int>p;
inline void Tarjan(int g)
{
    low[g]=id[g]=++cnt;
    sta[++top]=g;
    vis[g]=true;
    fur(i,0,(int)e[g].size()-1)
    {
        if(!id[e[g][i]])
        {
            Tarjan(e[g][i]);
            low[g]=min(low[g],low[e[g][i]]);
        }
        else if(vis[e[g][i]]) low[g]=min(low[g],id[e[g][i]]);
    }
    if(id[g]==low[g])
    {
        ++all;
        do
        {
            int tp=sta[top];
            sum[all]+=w[tp];
            vis[tp]=false;
            bel[tp]=all;
        }while(sta[top--]!=g);
    }
}
inline void spfa(int g)
{
    fur(i,1,all) dis[i]=0,viss[i]=false;
    int s=bel[g];
    p.push_back(s);
    dis[s]=sum[s];
    viss[s]=true;
    while(!p.empty())
    {
        int hd=p.front();
        p.pop_front();
        viss[hd]=false;
        fur(i,0,(int)f[hd].size()-1)
        {
            if(f[hd][i].second+dis[hd]>dis[f[hd][i].first])
            {
                dis[f[hd][i].first]=dis[hd]+f[hd][i].second;
                if(!viss[f[hd][i].first])
                {
                    viss[f[hd][i].first]=true;
                    if(!p.empty())
                    {
                        if(dis[f[hd][i].first]>dis[p.front()]) p.push_front(f[hd][i].first);
                        else p.push_back(f[hd][i].first);
                    }
                    else p.push_back(f[hd][i].first);
                }
            }
        }
    }
}
jinitaimei main()
{
    int n=in,m=in;
    fur(i,1,m)
    {
        u[i]=in,v[i]=in;
        if(u[i]==v[i]) continue;
        e[u[i]].push_back(v[i]);
    }
    fur(i,1,n) w[i]=in;
    fur(i,1,n) if(!id[i]) Tarjan(i);
    fur(i,1,m) if(bel[u[i]]!=bel[v[i]]) f[bel[u[i]]].push_back(nm(bel[v[i]],sum[bel[v[i]]]));
    int s=in,p=in;
    fur(i,1,p) bar[i]=in;
    spfa(s);
    int ans=0;
    fur(i,1,p) ans=max(ans,dis[bel[bar[i]]]);
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ALANALLEN21LOVE28/p/11313034.html
今日推荐