Codeforces Round #536 (Div. 2)

A. Lunar New Year and Cross Counting

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll; 
const int maxn=510;
int n;
char s[maxn][maxn];
int cnt;
int main(){
    while(cin>>n)
    {
        for(int i=1;i<=n;i++){
            scanf("%s",s[i]+1);
        }
        cnt=0;
        for(int i=2;i<n;i++)
        {
            for(int j=2;j<n;j++)
            {
                if(s[i-1][j-1]=='X'&&s[i+1][j-1]=='X'&&s[i][j]=='X'&&s[i-1][j+1]=='X'&&s[i+1][j+1]=='X')cnt++;
            }
        }
        cout<<cnt<<endl;
    }
}
View Code

B. Lunar New Year and Food Ordering

题意:(翻译来自洛谷)

思路:

  如果在一个菜品够买的情况下,当然是直接买,但是如果不够的话,就需要按照一定的优先级来维护这些物品了,显然是优先队列,优先队列中的元素只存储id和cost,然后剩余的量用一个r数组来保存,如果从优先队列里pop出来的东西剩余量为0就直接扔掉。

  B题居然会这么麻烦。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll; 
const int maxn=100010;
int n,m;
struct node{
    int id;
    ll cost;
    friend bool operator<(const node &a,const node &b){
        if(a.cost-b.cost)return a.cost>b.cost;
        return a.id>b.id;
    }
}a[maxn];
priority_queue<node >q;
ll r[maxn];
ll ans[maxn];
int main(){
    while(cin>>n>>m){
        clr(ans,0);
        while(!q.empty())q.pop();
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&r[i]);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i].cost);
            a[i].id=i;
            q.push(a[i]);
        }
        for(int i=1;i<=m;i++)
        {
            int t;
            ll d;
            scanf("%d%lld",&t,&d);
            ans[i]+=min(d,r[t])*a[t].cost;
            ll v=min(d,r[t]);
            d-=v;
            r[t]-=v;
            while(d>0){
                if(q.empty())break;
                node s=q.top();
                if(r[s.id]==0){
                    q.pop();
                    continue;
                }
                v=min(d,r[s.id]);
                ans[i]+=v*a[s.id].cost;
                d-=v;
                r[s.id]-=v;
            }
            if(d>0){
                ans[i]=0;
            }
        }
        for(int i=1;i<=m;i++)
        {
            printf("%lld
",ans[i]);
        }
    }
}
View Code

C. Lunar New Year and Number Division

思路:可以证明(等会证明)要两两分组,并且从小到大排,然后i 和n-i+1位置结合是最小的。

上面结论的两部分,后面一部分很好证明,个人认为前面的一部分有点难证明,其他博客的证明对这个两两分组最优讲的都不是很详细,某天在群里和大佬讨论后,大佬证明两两结合比三三结合更优。

这里面a是两个数字相加,d也是两个数字的相加,所以就是两两组合和三三组合。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll; 
const int maxn=300010;
int n;
ll a[maxn];
ll ans;
int main(){
    while(cin>>n)
    {
        ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);    

    }
        sort(a+1,a+1+n);
        for(int i=1;i<=n/2;i++)
        {
            ans+=(a[i]+a[n-i+1])*(a[i]+a[n-i+1]);
        }
        cout<<ans<<endl;
    }
}
View Code

D. Lunar New Year and a Wander

题意:在一个连通图上从1出发,每次到一个没有到达过的城市,记录标号,城市可以来回走,求字典序最小的路径。

思路:每到一个新城市,就把这个城市可以到达的城市标号塞入一个优先队列,优先弹出最小的标号即可。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll; 
const int maxn=100010;
vector<int >ve[maxn];
bool vis[maxn];
int n,m,u,v;
int ans[maxn],tot;
void init(){
    for(int i=1;i<=n;i++)
    {
        ve[i].clear();
    }
    clr(vis,0);
    tot=0;
}
priority_queue<int >q;
int main(){
    while(cin>>n>>m)
    {
        init();
        while(m--)
        {
            scanf("%d%d",&u,&v);
            ve[u].push_back(v);
            ve[v].push_back(u);
        }
        q.push(-1);
        vis[1]=1;
        while(tot<n)
        {
            int u=-q.top();
            q.pop();
            ans[++tot]=u;
            for(auto it:ve[u]){
                if(vis[it])continue;
                vis[it]=1;
                q.push(-it);
            }
        }
        for(int i=1;i<=tot;i++)
        {
            printf("%d%c",ans[i]," 
"[i==tot]);
        }
    }
}
View Code

E. Lunar New Year and Red Envelopes

题意:翻译来自洛谷

思路:

  将红包按价格从小打到排序,相同的按d从小到大排序,然后依次用线段树来更新,就可以得到在任意一秒如果抢红包,抢的是哪个红包,由于这个排序,所以如果后面的红包把前面的红包覆盖掉了,也是优先级高的覆盖了优先级低的。

  然后就是dp了,如果不考虑d的话,我们从前往后用一个二维dp就很好做了,但是现在这个d存在,要怎么办呢,我们倒着dp,并且转移的时候 $ f[i][j]=min(f[i+1][j-1],f[a[x].d+1][j]+a[x].w) $ x就是在第i秒抢到的红包标号。

  由于s<t<d,所以这个dp保证了一个红包不会被抢两次。

吐槽自己,居然想用普通的树状数组完成区间改值,单点查询的操作,蠢的一批。。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll; 
const int maxn=100010;
int n,m,k;
ll c[maxn];
ll f[maxn][210];
struct node{
    int s,t,d;
    ll w;
    friend bool operator<(const node &a,const node &b)
    {
        if(a.w!=b.w)return a.w<b.w;;
        return a.d<b.d;
    }
}a[maxn];
ll num[maxn];
struct segNode{
    ll sum,lazy;
}tr[maxn<<2];
void build(int o,int l,int r){
    if(l==r){
        tr[o].sum=0;
        tr[o].lazy=-1;
        return ;
    }
    int mid=(l+r)>>1;
    build(o<<1,l,mid);
    build((o<<1)|1,mid+1,r);
    tr[o].sum=tr[o<<1].sum+tr[(o<<1)|1].sum;
    tr[o].lazy=-1;
}
void pushup(int o){
    tr[o].sum=tr[o<<1].sum+tr[o<<1|1].sum;
}
void pushdown(int o,int l,int r){
    if(tr[o].lazy!=-1){
        tr[o<<1].lazy=tr[o].lazy;
        tr[o<<1|1].lazy=tr[o].lazy;
        int mid=(l+r)>>1;
        tr[o<<1].sum=tr[o].lazy*(mid-l+1);
        tr[o<<1|1].sum=tr[o].lazy*(r-mid);
        tr[o].lazy=-1;
    }
}
void update(int o,int l,int r,int ql,int qr,ll val){
    if(ql<=l&&r<=qr){
        tr[o].lazy=val;
        tr[o].sum=val*(r-l+1);
        return;
    }
    pushdown(o,l,r);
    int mid=l+((r-l)>>1);
    if(ql<=mid)update(o<<1,l,mid,ql,qr,val);
    if(qr>=mid+1)update(o<<1|1,mid+1,r,ql,qr,val);
    pushup(o);
}
ll query(int o,int l,int r,int ql,int qr){
    if(ql<=l&&qr>=r)return tr[o].sum;
    pushdown(o,l,r);
    int mid=(l+r)>>1;
    ll ans=0;
    if(ql<=mid)ans=query(o<<1,l,mid,ql,qr);
    if(qr>=mid+1)ans+=query(o<<1|1,mid+1,r,ql,qr);
    return ans;
}

int main(){
    while(cin>>n>>m>>k)
    {
        clr(c,0);
        clr(num,0);
        clr(f,0);
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d%d%lld",&a[i].s,&a[i].t,&a[i].d,&a[i].w);
        }
        sort(a+1,a+1+k);
        build(1,1,n);
        for(int i=1;i<=k;i++)
        {
            update(1,1,n,a[i].s,a[i].t,(ll)i);
        }
        for(int i=1;i<=n;i++)
        {
            num[i]=query(1,1,n,i,i);
        }
        for(int i=n;i>0;i--)
        {
            if(num[i]==0)
            {
                for(int j=0;j<=m;j++)
                {
                    f[i][j]=f[i+1][j];
                }
                continue;
            }
            int x=num[i];
            f[i][0]=f[a[x].d+1][0]+a[x].w;
            for(int j=1;j<=m;j++)
            {
                f[i][j]=min(f[i+1][j-1],f[a[x].d+1][j]+a[x].w);
            }
        }
        printf("%lld
",f[1][m]);
    }
}
View Code

F. Lunar New Year and a Recursive Sequence

原文地址:https://www.cnblogs.com/mountaink/p/10358476.html