Genshin Master (第二十届浙大城市学院程序设计竞赛) (时间戳,减法思维) 或者(离散化+差分 ||char数组暴力差法的做法)

题目大意:

 

 就是这个游戏,有6个音轨, 然后用单手操作,(5个手指头)最多只能操作5个音轨的内容, 给出每一个音轨的情况, 问, 最多可以拿多少分

思路:

  • 利用扫描线, 在同一个时刻内,尽可能的拿多的分数->有多少拿多少,有6个->拿5个
  • 因此就利用减法思维: 先把6个总的分拿到 - 6个音轨同时出现的情况, 
  • 同时出现的情况, 利用 时间戳思想去解决, 等cnt=6且是结束点的时候, 就加上这一部分的和就行了,具体 看代码
#include <bits/stdc++.h>
using namespace std;
#define ri int
#define M 2000005

int n,m,k;
struct node{
    int val;
    int id;
    int po;
    bool operator <(const node &t)const
    {
        if(val==t.val) return po<t.po;
        return val<t.val;
    }
}p[M];

int vis[M];
int now=0;
int main() {

    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    
    long long ans=0;
    int m=0;
    for(ri k=1;k<=6;k++)
    {
        cin>>n;m+=n;
        for(ri i=1;i<=n;i++)
        {
            now++;
            cin>>p[now].val;
            
            p[now].po=1;
            p[now].id=i;
            now++;
            cin>>p[now].val;
            p[now].po=2;
            p[now].id=i;
            ans+=p[now].val-p[now-1].val+1;
        }
    }
    sort(p+1,p+1+m*2);
    int l=0;
    int cnt=0;
    for(ri i=1;i<=m*2;i++)
    {
        if(p[i].po==1)
        {
            cnt++;
            l=p[i].val;
        }else
        {
            if(cnt==6)
            {
                ans-=p[i].val-l+1;    
            }    
            cnt--;
        }
    
    }
    
    
    cout<<ans;

}
View Code

题解思路:

  • 这道题本质,就是区间覆盖问题, 看同一个时间内被多少个音轨覆盖,然后来个min(5,)
  • 但是发现数据范围很大,于是离散化处理即可. 
#include<bits/stdc++.h>
using namespace std;
#define ll long long

//#define int long long

const int N = 2e5 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
#define pi acos(-1.0)


void solve()
{
    map<int,int>pre;
    for(int i=1;i<=6;i++)
    {
        int n;
        cin>>n;
        for(int j=1;j<=n;j++)
        {
            int l,r;
            cin>>l>>r;
            pre[l]++;
            pre[r+1]--;
        }
    }
    ll ans=0;
    vector<pair<int,int>>vt;
    for(auto i:pre)
    {
        vt.push_back(i);
    }
    int sum=0;
    for(int i=0;i<vt.size();i++)
    {
        sum+=vt[i].second;
        ans+=min(sum,5)*(vt[i+1].first-vt[i].first);
    }
    
    cout<<ans<<'\n';
}
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t = 1;
    //cin>>t;
    while (t--)
    {
        solve();
    }
}
别人的赏心悦目的代码

思路3:

  • 利用char数组去存的,不用离散的保留循环做法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MM=1e8+7;
char a[MM];
int main(){
    int n,s,t;
    ll sum=0;
    for(int i=0;i<6;i++){
        cin>>n;
        while(n--){
            cin>>s>>t;
            a[s]++;
            a[t+1]--;
            sum+=t-s+1;
        }
    }
    int flag=0;
    for(int i=0;i<=MM;i++){
        flag+=a[i];
        if(flag==6){
            sum--;
        }
    }
    cout<<sum;
    return 0;
}
View Code

 

posted @ 2023-04-02 15:57  VxiaohuanV  阅读(211)  评论(0编辑  收藏  举报