BZOJ 4236~4247 题解

BZOJ 4236 JOIOJI

f[i][0..2]表示前i个字符中′J′/′O′/′I′的个数

将二元组<f[i][0]?f[i][1],f[i][1]?f[i][2]>扔进map,记录一下最早出现的时间

对于每个位置去map里面查一下即可

时间复杂度O(nlogn)

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
int n,ans;
char s[M];
map<pair<int,int>,int> m;
int sum[3][M];
int main()
{
    int i;
    cin>>n;
    scanf("%s",s+1);
    m[make_pair(0,0)]=0;
    for(i=1;i<=n;i++)
    {
        sum[0][i]=sum[0][i-1]+(s[i]==‘J‘);
        sum[1][i]=sum[1][i-1]+(s[i]==‘O‘);
        sum[2][i]=sum[2][i-1]+(s[i]==‘I‘);
        if( m.find( make_pair(sum[0][i]-sum[1][i],sum[1][i]-sum[2][i]) )==m.end() )
            m[make_pair(sum[0][i]-sum[1][i],sum[1][i]-sum[2][i])]=i;
        else
            ans=max(ans,i-m[make_pair(sum[0][i]-sum[1][i],sum[1][i]-sum[2][i])]);
    }
    cout<<ans<<endl;
    return 0;
}

BZOJ 4237 稻草人

按y坐标分治,每层分治内部按x坐标排序后,上层维护一个单调递减的单调栈,下层维护一个单调递增的单调栈

然后对于上层每个元素去下层二分即可

时间复杂度O(nlog2n)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;

struct Point{
    int x,y;
    friend istream& operator >> (istream &_,Point &p)
    {
        return scanf("%d%d",&p.x,&p.y),_;
    }
}points[M],_points[M];
bool Compare_x (const Point &p1,const Point &p2)
{
    return p1.x < p2.x ;
}
bool Compare_y (const Point &p1,const Point &p2)
{
    return p1.y < p2.y ;
}

int n;
long long ans;
Point stack1[M],stack2[M];
int top1,top2;

void Divide_And_Conquer(int l,int r)
{
    if(l==r) return ;
    int i,j,mid=l+r>>1;
    int _l=l,_r=mid+1;
    for(i=l;i<=r;i++)
        if(points[i].y<=mid)
            _points[_l++]=points[i];
        else
            _points[_r++]=points[i];
    memcpy(points+l,_points+l,sizeof(Point)*(r-l+1) );
    for(top1=top2=0,j=l,i=mid+1;i<=r;i++)
    {
        for(;j<=mid&&points[j].x<points[i].x;j++)
        {
            while(top2&&points[j].y>stack2[top2].y)
                top2--;
            stack2[++top2]=points[j];
        }
        while(top1&&points[i].y<stack1[top1].y)
            top1--;
        stack1[++top1]=points[i];
        int pos=upper_bound(stack2+1,stack2+top2+1,stack1[top1-1],Compare_x)-stack2;
        ans+=top2-pos+1;
    }
    Divide_And_Conquer(l,mid);
    Divide_And_Conquer(mid+1,r);
}

int main()
{
    static pair<int,int*> b[M];
    int i;
    cin>>n;
    for(i=1;i<=n;i++)
        cin>>points[i];

    for(i=1;i<=n;i++)
        b[i]=make_pair(points[i].x,&points[i].x);
    sort(b+1,b+n+1);
    for(i=1;i<=n;i++)
        *b[i].second=i;

    for(i=1;i<=n;i++)
        b[i]=make_pair(points[i].y,&points[i].y);
    sort(b+1,b+n+1);
    for(i=1;i<=n;i++)
        *b[i].second=i;

    sort(points+1,points+n+1,Compare_x);
    Divide_And_Conquer(1,n);
    cout<<ans<<endl;
    return 0;
}

BZOJ 4238 电压

看到这题想要直接上动态二分图的举手……

任选一棵生成树,考虑选择树边或者非树边

定义一条非树边为好边当且仅当两个端点在树上的距离为奇数,否则为坏边

如果坏边只有一条那么这条坏边是可选的

如果一条树边被所有的坏边覆盖而且不被好边覆盖那么这条边是可选的

DFS一遍即可

由于DFS树没有横叉边只有返祖边因此求LCA是O(1)的 这样复杂度就是O(n+m)的了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
struct abcd{
    int to,next;
}table[M<<1];
int head[M],tot=1;
int n,m,ans,good_cnt,bad_cnt;
int dpt[M],fa[M],good[M],bad[M];
bool v[M];
void Add(int x,int y)
{
    table[++tot].to=y;
    table[tot].next=head[x];
    head[x]=tot;
}
void DFS(int x,int from)
{
    int i;
    v[x]=true;
    dpt[x]=dpt[fa[x]]+1;
    for(i=head[x];i;i=table[i].next)
        if(i^from^1)
        {
            if(!v[table[i].to])
            {
                fa[table[i].to]=x;
                DFS(table[i].to,i);
                good[x]+=good[table[i].to];
                bad[x]+=bad[table[i].to];
            }
            else
            {
                if(dpt[table[i].to]>dpt[x])
                    continue;
                if(dpt[x]-dpt[table[i].to]&1)
                    good[x]++,good[table[i].to]--,good_cnt++;
                else
                    bad[x]++,bad[table[i].to]--,bad_cnt++;
            }
        }
}
int main()
{
    int i,x,y;
    cin>>n>>m;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        Add(x,y);
        Add(y,x);
    }
    for(i=1;i<=n;i++)
        if(!v[i])
            DFS(i,0);
    for(i=1;i<=n;i++)
        if(fa[i]&&bad[i]==bad_cnt&&!good[i])
            ++ans;
    if(bad_cnt==1)
        ++ans;
    cout<<ans<<endl;
}

BZOJ 4239 巴士走读

将二元组<站点,时间>看做一个点,那么点数是O(m)的

每辆巴士连一条边,每个点向下一个时间连边,然后将所有边反向

枚举终点站的每一个时间,加入队列广搜,得到最晚多久到达1号站点可以在这个时间到达终点站

然后对于每个询问去数组中二分即可

时间复杂度O((m+q)logm)

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;

namespace Hash_Set{
    struct List{
        int x,y,val;
        List *next;
        List(int _,int __,List *___):
            x(_),y(__),val(0),next(___) {}
    }*head[3001][3001];
    int& Hash(int x,int y)
    {
        int pos1=x%3001;
        int pos2=y%3001;
        List *temp;
        for(temp=head[pos1][pos2];temp;temp=temp->next)
            if(temp->x==x&&temp->y==y)
                return temp->val;
        return (head[pos1][pos2]=new List(x,y,head[pos1][pos2]))->val;
    }
}

struct abcd{
    int to,next;
}table[900900];
int head[600600],tot;

int n,m,k,now=-1;
pair<int,int> ans[600600];int top;

vector<int> stack[M];

int T;
pair<int,int> hash[600600];

bool v[600600];
int q[600600],r,h;

void Add(int x,int y)
{
    table[++tot].to=y;
    table[tot].next=head[x];
    head[x]=tot;
}
int Hash(int x,int y)
{
    int &val=Hash_Set::Hash(x,y);
    if( !val )
        hash[val=++T]=make_pair(x,y);
    return val;
}
void BFS()
{
    int i;
    while(r!=h)
    {
        int x=q[++h];
        for(i=head[x];i;i=table[i].next)
            if(!v[table[i].to])
            {
                v[table[i].to]=true;
                q[++r]=table[i].to;
            }
        if(hash[x].first==1)
            now=max(now,hash[x].second);
    }
}
int main()
{
    int i,j,x,y,_x,_y;
    cin>>n>>m;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&x,&y,&_x,&_y);
        stack[x].push_back(_x);
        stack[y].push_back(_y);
        Add( Hash(y,_y) , Hash(x,_x) );
    }
    for(i=1;i<=n;i++)
    {
        sort(stack[i].begin(),stack[i].end());
        for(j=1;j<(signed)stack[i].size();j++)
            if( stack[i][j]!=stack[i][j-1] )
                Add( Hash(i,stack[i][j]) , Hash(i,stack[i][j-1]) );
    }
    for(i=0;i<(signed)stack[n].size();i++)
    {
        int temp=Hash(n,stack[n][i]);
        if(v[temp]) continue;
        v[temp]=true;q[++r]=temp;
        BFS();
        ans[++top]=make_pair(stack[n][i],now);
    }
    ans[0].second=-1;
    cin>>k;
    for(i=1;i<=k;i++)
    {
        scanf("%d",&x);
        printf("%d\n",(lower_bound(ans+1,ans+top+1,pair<int,int>(x,0x3f3f3f3f) )-1)->second);
    }
    return 0;
}

BZOJ 4240 有趣的家庭菜园

从小到大枚举高度,由于无论将这株草移动到左侧还是右侧都对比它高的植物没有影响,因此贪心选择代价最小的方向即可

故答案为∑min(a[1…i-1]中大于a[i]的数的数量,a[i+1…n]中大于a[i]的数的数量)

用树状数组即可 时间复杂度O(nlogn)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;
int n,m,a[M],f[M],g[M];
long long ans;
namespace BIT{
    int c[M];
    void Initialize()
    {
        memset(c,0,sizeof c);
    }
    void Update(int x)
    {
        for(;x;x-=x&-x)
            c[x]++;
    }
    int Query(int x)
    {
        int re=0;
        for(;x<=m;x+=x&-x)
            re+=c[x];
        return re;
    }
}
int main()
{
    static pair<int,int*> b[M];
    int i;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&b[i].first);
        b[i].second=&a[i];
    }
    sort(b+1,b+n+1);
    for(i=1;i<=n;i++)
    {
        if(i==1||b[i].first!=b[i-1].first)
            ++m;
        *b[i].second=m;
    }

    for(i=1;i<=n;i++)
    {
        BIT::Update(a[i]);
        f[i]=BIT::Query(a[i]+1);
    }

    BIT::Initialize();
    for(i=n;i;i--)
    {
        BIT::Update(a[i]);
        g[i]=BIT::Query(a[i]+1);
    }

    for(i=1;i<=n;i++)
        ans+=min(f[i],g[i]);
    cout<<ans<<endl;

    return 0;
}

BZOJ 4241 历史研究

分块,记录第i块到第j块的答案以及前i块中数字j出现了多少次,然后每次询问先调用整块的答案,然后枚举零碎的部分进行更新即可

时间复杂度O(qn√)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
#define B 350
using namespace std;
int n,m,q,b;
int a[M],ori[M];
int l[B],r[B],belong[M];
int block_cnt[B][M];//block_cnt[i][j]表示前i块中数字j的出现次数
long long block_ans[B][B];//block_ans[i][j]表示从第i块到第j块的最大重要度
long long Query(int l,int r)
{
    static int cnt[M],tim[M],T;
    int i,_l=belong[l],_r=belong[r];
    long long re=block_ans[_l+1][_r-1];
    ++T;
    if(_l==_r)
    {
        for(i=l;i<=r;i++)
        {
            if(tim[a[i]]!=T)
                tim[a[i]]=T,cnt[a[i]]=0;
            re=max(re,(long long)ori[a[i]]*++cnt[a[i]]);
        }
        return re;
    }
    for(i=l;i<=::r[_l];i++)
    {
        if(tim[a[i]]!=T)
            tim[a[i]]=T,cnt[a[i]]=block_cnt[_r-1][a[i]]-block_cnt[_l][a[i]];
        re=max(re,(long long)ori[a[i]]*++cnt[a[i]]);
    }
    for(i=r;i>=::l[_r];i--)
    {
        if(tim[a[i]]!=T)
            tim[a[i]]=T,cnt[a[i]]=block_cnt[_r-1][a[i]]-block_cnt[_l][a[i]];
        re=max(re,(long long)ori[a[i]]*++cnt[a[i]]);
    }
    return re;
}
int main()
{
    static pair<int,int*> c[M];
    int i,j,x,y;

    cin>>n>>q;
    b=int(sqrt(n)+1e-7);

    for(i=1;i<=n;i++)
    {
        scanf("%d",&c[i].first);
        c[i].second=&a[i];
    }
    sort(c+1,c+n+1);
    for(i=1;i<=n;i++)
    {
        if(i==1||c[i].first!=c[i-1].first)
            ori[++m]=c[i].first;
        *c[i].second=m;
    }

    for(i=1;i<=n;i++)
        belong[i]=(i-1)/b+1;
    for(i=1;(i-1)*b+1<=n;i++)
        l[i]=(i-1)*b+1,r[i]=min(i*b,n);

    for(i=1;i<=n;i++)
        block_cnt[belong[i]][a[i]]++;
    for(i=1;l[i];i++)
        for(j=1;j<=n;j++)
            block_cnt[i][j]+=block_cnt[i-1][j];
    static int cnt[M];
    long long ans;
    for(i=1;l[i];i++)
    {
        memset(cnt,0,sizeof cnt);ans=0;
        for(j=l[i];j<=n;j++)
        {
            ans=max(ans,(long long)ori[a[j]]*++cnt[a[j]]);
            if(j==r[belong[j]])
                block_ans[i][belong[j]]=ans;
        }
    }

    for(i=1;i<=q;i++)
    {
        scanf("%d%d",&x,&y);
        #ifdef ONLINE_JUDGE
            printf("%lld\n",Query(x,y));
        #else
            printf("%I64d\n",Query(x,y));
        #endif
    }
    return 0;
}

BZOJ 4242 水壶

把每栋建筑物扔进队列跑BFS,对于每块空地记录这块空地是被哪栋建筑物搜到的,以及距离是多少

然后不同所属的空地之间连边,跑货车运输即可

时间复杂度O(whα(p)+qlogp)

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
int n,m,k,Q;
char map[2020][2020];
pair<int,int> v[2020][2020];
pair<int,int> q[4004004];int r,h;
vector< pair<int,int> > stack[4004004];
int fa[M],dis[M],dpt[M];
void BFS()
{
    int i;
    while(r!=h)
    {
        pair<int,int> x=q[++h];
        for(i=0;i<4;i++)
        {
            pair<int,int> y(x.first+dx[i],x.second+dy[i]);
            if( y.first==0 || y.second==0 || y.first==n+1 || y.second==m+1 || map[y.first][y.second]==‘#‘ )
                continue;
            if( v[y.first][y.second]==pair<int,int>(0,0) )
                q[++r]=y,v[y.first][y.second]=pair<int,int>(v[x.first][x.second].first+1,v[x.first][x.second].second);
            else if(v[y.first][y.second].second!=v[x.first][x.second].second)
                stack[v[y.first][y.second].first+v[x.first][x.second].first].push_back(pair<int,int>(v[y.first][y.second].second,v[x.first][x.second].second));
        }
    }
}
namespace Union_Find_Set{
    int fa[M],rank[M];
    int Find(int x)
    {
        if(!fa[x]||fa[x]==x)
            return fa[x]=x;
        return fa[x]=Find(fa[x]);
    }
}
void Kruskal()
{
    using namespace Union_Find_Set;
    int i,j;
    for(i=0;i<=n*m;i++)
        for(j=0;j<(signed)stack[i].size();j++)
        {
            int x=Find(stack[i][j].first);
            int y=Find(stack[i][j].second);
            if(x==y)
                continue;
            if(rank[x]>rank[y])
                swap(x,y);
            if(rank[x]==rank[y])
                ++rank[y];
            Union_Find_Set::fa[x]=y;
            ::fa[x]=y;dis[x]=i;
        }
}
int Depth(int x)
{
    if(dpt[x])
        return dpt[x];
    if(!fa[x])
        return dpt[x]=1;
    return dpt[x]=Depth(fa[x])+1;
}
int Query(int x,int y)
{
    if( Union_Find_Set::Find(x)!=Union_Find_Set::Find(y) )
        return -1;
    int re=0;
    if(Depth(x)<Depth(y))
        swap(x,y);
    while(Depth(x)>Depth(y))
        re=max(re,dis[x]),x=fa[x];
    while(x!=y)
        re=max(re,dis[x]),re=max(re,dis[y]),x=fa[x],y=fa[y];
    return re;
}
int main()
{
    int i,x,y;
    cin>>n>>m>>k>>Q;
    for(i=1;i<=n;i++)
        scanf("%s",map[i]+1);
    for(i=1;i<=k;i++)
    {
        scanf("%d%d",&x,&y);
        v[x][y]=pair<int,int>(0,i);
        q[++r]=pair<int,int>(x,y);
    }
    BFS();
    Kruskal();
    for(i=1;i<=Q;i++)
    {
        scanf("%d%d",&x,&y);
        printf("%d\n",Query(x,y));
    }
    return 0;
}

BZOJ 4243 交朋友

把能进行会议的国家之间都用并查集连接起来,然后把每个进行过会议的国家扔进队列跑BFS,将搜到的国家用并查集连接

最终答案等于每个单点的出度个数+2*C(每个集合的大小,2)

时间复杂度O((n+m)α(n))

#include <set>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
int n,m;
long long ans;
set<int> map[M];
bool v[M];
int q[M],r,h;
namespace Union_Find_Set{
    int fa[M],rank[M],size[M];
    int Find(int x)
    {
        if(!fa[x])
            fa[x]=x,size[x]=1;
        if(fa[x]==x)
            return x;
        return fa[x]=Find(fa[x]);
    }
    void Union(int x,int y)
    {
        x=Find(x);y=Find(y);
        if(x==y) return ;
        if(rank[x]>rank[y])
            swap(x,y);
        if(rank[x]==rank[y])
            ++rank[y];
        fa[x]=y;size[y]+=size[x];
    }
}
int main()
{
    using namespace Union_Find_Set;
    int i,x,y;
    set<int>::iterator it;
    cin>>n>>m;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        map[x].insert(y);
    }
    for(i=1;i<=n;i++)
        for(it=map[i].begin();it!=map[i].end();it++)
            if( map[*it].find(i)!=map[*it].end() )
                Union(i,*it);
    for(i=1;i<=n;i++)
        if(map[i].size()>1)
        {
            int temp=*map[i].begin();
            for(it=map[i].begin(),it++;it!=map[i].end();it++)
                Union(*it,temp);
        }
    for(i=1;i<=n;i++)
        if(size[Find(i)]!=1)
            v[i]=1,q[++r]=i;
    while(r!=h)
    {
        x=q[++h];
        for(it=map[x].begin();it!=map[x].end();it++)
        {
            Union(x,*it);
            if(!v[*it]) v[*it]=true,q[++r]=*it;
        }
    }
    for(i=1;i<=n;i++)
        if(Find(i)==i)
        {
            if(size[i]==1)
                ans+=map[i].size();
            else
                ans+=(long long)size[i]*(size[i]-1);
        }
    cout<<ans<<endl;
    return 0;
}

BZOJ 4244 邮戳拉力赛

从车站0沿上行车道到达车站n的路径必走,除掉这条路径后图中剩下了一些环

令fi,j表示已经经过了前i个邮戳台,并且从下行站台走到上行站台的次数-从上行站台走到下行站台的次数为j的最短时间

每层跑个完全背包即可 时间复杂度O(n2)

顺便吐槽:官方能把スタンプラリー后面注释一个“Collecting Stamps”我真是醉如烂泥。。。

谁能告诉我Stamp Rally到底咋翻译……

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 3030
using namespace std;
int n,t;
long long f[M][M];
//f[i][j]表示已经到达过第1...i个邮戳,剩余的从上行站台走到下行站台的次数为j的最短时间
int u[M],v[M],d[M],e[M];
int main()
{
    int i,j;
    cin>>n>>t;
    for(i=1;i<=n;i++)
        scanf("%d%d%d%d",&u[i],&v[i],&d[i],&e[i]);
    memset(f,0x3f,sizeof f);
    f[0][0]=0;
    for(i=1;i<=n;i++)
    {
        for(j=0;j<=n;j++)
            f[i-1][j]+=j*t*2;
        for(j=1;j<=n;j++)
            f[i][j]=min(f[i][j],f[i-1][j-1]+d[i]+v[i]);
        for(j=0;j<n;j++)
            f[i][j]=min(f[i][j],f[i-1][j+1]+u[i]+e[i]);
        for(j=1;j<=n;j++)
            f[i][j]=min(f[i][j],f[i-1][j]+d[i]+e[i]);
        for(j=0;j<=n;j++)
            f[i][j]=min(f[i][j],f[i-1][j]+u[i]+v[i]);
        for(j=1;j<=n;j++)
            f[i][j]=min(f[i][j],f[i][j-1]+d[i]+v[i]);
        for(j=n-1;~j;j--)
            f[i][j]=min(f[i][j],f[i][j+1]+u[i]+e[i]);
    }
    cout<<f[n][0]+t*(n+1)<<endl;
    return 0;
}

BZOJ 4246 两个人的星座

这应该是这次合宿最难的一道题了……

考虑两个三角形,如果这两个三角形相离,那么一定可以做出两条内公切线,否则做不出来

枚举一个点,以这个点为中心按极角序枚举另一个点,连接这两个点作出一条公切线,那么这两个三角形分别分布在这条线的两端,统计出两侧每种颜色的点之后乘法原理即可

时间复杂度O(n2logn)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 3030
#define PI 3.1415926535897932384626433832795028841971
using namespace std;
struct Point{
    int x,y;
    Point() {}
    Point(int _,int __):
        x(_),y(__) {}
    friend Point operator + (const Point &p1,const Point &p2)
    {
        return Point(p1.x+p2.x,p1.y+p2.y);
    }
    friend Point operator - (const Point &p1,const Point &p2)
    {
        return Point(p1.x-p2.x,p1.y-p2.y);
    }
    friend double Arctan2(const Point &p)
    {
        double re=atan2(p.y,p.x);
        if(re<=0) re+=PI;
        return re;
    }
}O;
pair<Point,int> points[M],stack[M];
int n,top;
long long ans;
void Calculate(int c)
{
    static pair<double,int> b[M];
    static bool v[M];
    static pair<Point,int> _stack[M];
    int i,cnt[2][3]={{0,0,0},{0,0,0}};
    for(i=1;i<=top;i++)
        b[i]=pair<double,int>(Arctan2(stack[i].first-O),i);
    sort(b+1,b+top+1);
    for(i=1;i<=top;i++)
        _stack[i]=stack[b[i].second];
    memcpy(stack+1,_stack+1,sizeof(stack[0])*top);
    for(i=1;i<=top;i++)
        if( stack[i].first.y<O.y || stack[i].first.y==O.y && stack[i].first.x>O.x )
            cnt[v[i]=false][stack[i].second]++;
        else
            cnt[v[i]=true][stack[i].second]++;
    for(i=1;i<=top;i++)
    {
        cnt[v[i]][stack[i].second]--;
        int cnt0=1,cnt1=1;
        if(c!=0) cnt0*=cnt[false][0];
        if(c!=1) cnt0*=cnt[false][1];
        if(c!=2) cnt0*=cnt[false][2];
        if(stack[i].second!=0) cnt1*=cnt[true][0];
        if(stack[i].second!=1) cnt1*=cnt[true][1];
        if(stack[i].second!=2) cnt1*=cnt[true][2];
        ans+=(long long)cnt0*cnt1;
        cnt0=cnt1=1;
        if(c!=0) cnt0*=cnt[true][0];
        if(c!=1) cnt0*=cnt[true][1];
        if(c!=2) cnt0*=cnt[true][2];
        if(stack[i].second!=0) cnt1*=cnt[false][0];
        if(stack[i].second!=1) cnt1*=cnt[false][1];
        if(stack[i].second!=2) cnt1*=cnt[false][2];
        ans+=(long long)cnt0*cnt1;
        cnt[v[i]^=1][stack[i].second]++;
    }
}
int main()
{
    int i,j;
    cin>>n;
    for(i=1;i<=n;i++)
        scanf("%d%d%d",&points[i].first.x,&points[i].first.y,&points[i].second);
    for(i=1;i<=n;i++)
    {
        top=0;
        for(j=1;j<=n;j++)
            if(i!=j)
                stack[++top]=points[j];
        O=points[i].first;
        Calculate(points[i].second);
    }
    cout<<ans/4<<endl;
    return 0;
}

BZOJ 4247 挂饰

傻逼背包

时间复杂度O(n2)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 2020
using namespace std;
int n;
struct Array{
    long long a[M<<1];
    long long& operator [] (int x)
    {
        return a[min(max(x,-n),n)+2000];
    }
}f;
int main()
{
    int i,j,x,y;
    memset(&f,0xef,sizeof f);
    cin>>n;f[0]=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        x=1-x;
        if(x>0)
        {
            for(j=n;j>=-n;j--)
                f[j+x]=max(f[j+x],f[j]+y);
        }
        else
        {
            for(j=-n;j<=n;j++)
                f[j+x]=max(f[j+x],f[j]+y);
        }
    }
    long long ans=0;
    for(i=-n;i<=1;i++)
        ans=max(ans,f[i]);
    cout<<ans<<endl;
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-14 09:06:33

BZOJ 4236~4247 题解的相关文章

BZOJ 1179 Atm 题解

BZOJ 1179 Atm 题解 SPFA Algorithm Tarjan Algorithm Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口

函数式trie思想 &amp; Bzoj 3261 &amp; 3166 题解

[原题1] 3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 497  Solved: 215 [Submit][Status] Description 给定一个非负整数序列 {a},初始长度为 N. 有   M个操作,有以下两种操作类型: 1 .A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1. 2 .Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p] xor a[

BZOJ 1008 越狱 题解 裸快速幂

BZOJ 1008 越狱 题解 裸快速幂 1008: [HNOI2008]越狱 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7887  Solved: 3372[Submit][Status][Discuss] Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 Input 输入两个整数M,N.1<=M<

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,

斜率优化专题3——bzoj 3156 防御准备 题解

[原题] 3156: 防御准备 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 198  Solved: 107 [Submit][Status] Description Input 第一行为一个整数N表示战线的总长度. 第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai. Output 共一个整数,表示最小的战线花费值. Sample Input 10 2 3 1 5 4 5 6 3 1 2 Sample Output 18 HINT

bzoj 2506 calc 题解

[原题] 2506: calc Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 228  Solved: 112 Description 给一个长度为n的非负整数序列A1,A2,-,An.现有m个询问,每次询问给出l,r,p,k,问满足l<=i<=r且Ai mod p = k的值i的个数. Input 第一行两个正整数n和m. 第二行n个数,表示A1,A2,-,An. 以下m行,每行四个数分别表示l,r,p,k.满足1<=l<=r&

【醒目】【业界偷懒】【Public】BZOJ题目一句话题解整理

就当是复习一下自己做过的题,顺便提供一个简要题解给大家看. 做题时候实在想不出来看一下一句话题解,可以有一个提示的作用又不至于一下子知道了全部浪费了一道题吧.. 部分题目(如我A过得大部分奶牛题)是别人拿我的账号做的,不提供题解. 可能会漏掉很多做过的题..因为可能点页数不小心点错了什么的 UPD.本来想把那些没写过但是知道题解的也写了..但是写完这些已经累死了QAQ 已AC的题目(数学题均不提供分析过程,公式): 1000:A+B 1001:平面图最小割,转对偶图最短路 1002:矩阵树定理,

BZOJ 4236 JOIOJI(前缀和)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4236 [题目大意] 给出一个只包含三种字母的字符串,求出三种字母数量相等的最长子串 [题解] 我们记录三个字母的前缀和,我们发现只要一个区段左右端点前缀和之差相等, 就说明这个区段三个字母出现次数相等,其充要条件为SJ-SO和SO-SI相等, 所以我们在map中保存双关键字第一次出现的位置,每次查询当前位置和第一次出现位置的距离 求最大值即可. [代码] #include <cstd

BZOJ 2653 middle 题解

题意:一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给一个序列,并进行一些询问.每次询问起点在[a,b],终点在[c,d]的序列的中位数. 题解:首先有一个思路:对于一个序列S,假设它的中位数是m,则S中>=m的元素个数一定>=n 那么对于一个序列S和一个数m,我们将>=m的元素设置为1,其余为-1,得到一个新数列S‘.则$\sum S'$ >=0 对于每个询问我们二分一下m即可.如果在区间[a,d]内有一段包含[b,c