爱悠闲 > BZOJ 4236~4247 题解

BZOJ 4236~4247 题解

分类: BZOJ  |  标签: BZOJ  |  作者: popoqqq 相关  |  发布日期 : 2015-09-25  |  热度 : 112°

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;
}

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