2020.2.15模拟赛

剑与魔法

【问题描述】

万老师听说某大国很流行穿越,于是他就想写一个关于穿越的剧本。

闲话休提。话说老师穿越到了某一个剑与魔法的大陆。因为如此这般,所以老师从维娜艾那里得到了预言。老师一共被告知了若干件按顺序结算的 事件。这些事件分为两类:战役事件(CASE)、穿越回去事件(END)。战役事件可以选择是否参加,参加了之后会获得一定的金钱。每个END事件 发生需要至少参加一定数量的战役事件。特别的是,END事件如果满足要求就会强制发生。老师希望在大陆玩个够,所以他要求只有最后一个END事 件会发生。老师希望获得最多的金钱,所以求助于你。

【输入】

第一行一个数N,表示输入文件有多少行。 接下来每一行用空格隔开一个字符和一个整数。字符为“c”表示战役事件,接下来的整数表示这次涨RP顺带有多少钱;字符为“e”表示穿越回去 事件,接下来的整数代表至少要涨多少RP。最后一个事件保证是END事件。

【输出】

第一行一个整数,最多金钱数目。

若不可能则输出-1。

【输入输出样例】

dragons.in

5

c 10

c 12

e 2

c 1

e 2

dragons.out

13

【数据说明】

30%的数据满足 N<=20

60%的数据满足 N<=1,000

100%的数据满足 N<=200,000

每次涨RP事件赏金不超过10,000

穿越事件的要求不超过200,000 

用堆(优先队列)实现贪心策略。尽量从堆中取出金钱。

#include<bits/stdc++.h>
using namespace std;
priority_queue<int> q;
int main()
{
    int n,h=0;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        char c;
        cin>>c;
        int x;
        scanf("%d",&x);
        if (c=='c')
        {
            x=-x;
            q.push(x);
            h++;
        }
        else
        {
            if (i!=n)
            {
                for (int i=1;i<=h-x+1;i++)
                q.pop();
                if (h>=x) h=x-1;
            }
        }   
    }
    int ans=0;
    for (int i=1;i<=h;i++)
    {
        int x;
        x=q.top();
        q.pop();
        ans-=x;
    }
    printf("%d",ans);
}

矩形

【问题描述】

因为对polo忍无可忍, dzf使用圣剑在地上划出了许多纵横交错的沟壑来泄愤。这些沟壑都严格与X轴平行或垂直。 polo嘲笑了dzf无聊的行为,然后做了一件更加无聊的事。他蹲下来数这些沟壑的条数。数着数着,polo意识到一个问题,那就是因为圣剑的威力太大,划出的沟壑太多,地面就会塌陷。而如果两条水平的沟壑和两条垂直的沟壑相交组成了一个矩形,那么塌陷的危险就会进一步增加。现在polo已经数了n条沟壑,他想知道这些沟壑组成了多少个矩形。

【输入】

第一行一个数n,接下来每行4个数x1,y1,x2,y2,表示沟壑的两个端点(x1,y1),(x2,y2)

【输出】

一个数,组成的矩形个数。

【输入输出样例1】

rect.in

4

0 0 1 0

0 0 0 1

1 1 1 -1

1 1 0 1

rect.out

1

【输入输出样例2】

rect.in

8

1 0 4 0

2 1 2 0

0 0 0 3

2 2 2 3

3 3 3 -1

0 3 4 3

4 1 -1 1

3 2 -1 2

rect.out

6

【数据说明】

对于30%的数据,1<=n<=100

对于60%的数据,1<=n<=600

对于100%的数据,1<=n<=2000,坐标绝对值小于10^9,任意两条与X轴水平的沟壑之间没有交点,任意两条与X轴垂直的沟壑没有交点。

一开始打了个暴力O(n3)的算法,果然只拿了55分。

枚举两条垂直的线段,枚举一条水平线段,再枚举一条水平的与两者相交的线段k,明显能构成C(k,2)=k(k-1)/2个矩形。

但是O(n3)好像也能过,就优化了一点点吧,减少一点情况。

放两个代码对比。

55分代码。

#include<bits/stdc++.h>
const int N=200005;
using namespace std;
int n,nx,ny;
struct jsy 
{
    int x1,y1;
    int x2,y2;
}x[N],y[N];
int main() 
{
    cin>>n;
    for(int i=1;i<=n;i++) 
    {
        int t1,t2,t3,t4;
        cin>>t1>>t2>>t3>>t4;
        if(t2==t4) 
        {
            x[++nx].x1=min(t1,t3);
            x[nx].y1=t2;
            x[nx].x2=max(t1,t3);
            x[nx].y2=t4;
        }
        if(t1==t3) 
        {
            y[++ny].x1=t1;
            y[ny].y1=min(t2,t4);
            y[ny].x2=t3;
            y[ny].y2=max(t2,t4);
        }
    }
    if(n<4) 
    {
        printf("0");
        return 0;
    }
    long long ans=0;
    for(int i=1;i<=ny;i++)
    {
        for(int j=i+1;j<=ny;j++) 
        {
            int t=0;
            for(int k=1;k<=nx;k++) 
            {
                if(x[k].x1<=y[i].x1&&x[k].x1<=y[j].x1&&x[k].x2>=y[i].x1&&x[k].x2>=y[j].x1&&x[k].y1>=y[i].y1&&x[k].y1>=y[j].y1&&x[k].y1<=y[i].y2&&x[k].y1<=y[j].y2)
                t++;
            }
            ans+=t*(t-1)/2;
        }
    }   
    cout<<ans;
}

100分代码。

#include<bits/stdc++.h>
using namespace std;
const int N=2001;
struct ahj 
{
    int a,b,c,d;
}s[N],t[N];
int n,t1,t2;
int q[N][N],w[N][N],c[N]; 
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        if(b==d)
        {
            if(a>c) swap(a,c);
            s[++t1]=ahj{a,b,c,d};
        }
        else 
        {
            if(b>d) swap(b,d);
            t[++t2]=ahj{a,b,c,d};
        }
    }
    for(int i=1;i<=t1;i++)
    {
        for(int j=1;j<=t2;j++)
        {
            if(s[i].a<=t[j].a&&t[j].a<=s[i].c&&t[j].b<=s[i].b&&s[i].b<=t[j].d)
            {
                q[i][j]=1;
                w[i][++c[i]]=j;
            }
        }
    }
    int ans=0;
    for(int i=1;i<t1;i++)
    {
        for(int j=i+1;j<=t1;j++)
        {
            int k=0;
            int x=i,y=j;
            if(c[i]>c[j]) swap(x,y);
            for(int h=1;h<=c[x];h++)
            {
                if(q[y][w[x][h]]) k++;
            }
            ans+=k*(k-1)/2;
        }
    }
    printf("%d",ans);
    return 0;
}

但是正解貌似是线段树。

线段树+离散化,利用线段树的区间求和来解决,总时间复杂度为O(n2log2n)。

但是我没有写,没有代码就算了吧。


数列的GCD

【问题描述】

给出一个长度为N的数列{a[n]},1<=a[i]<=M(1<=i<=N)。

现在问题是,对于1到M的每个整数d,有多少个不同的数列b[1], b[2], ..., b[N],满足:

(1)1<=b[i]<=M(1<=i<=N);

(2)gcd(b[1], b[2], ..., b[N])=d;

(3)恰好有K个位置i使得a[i]<>bi

注:gcd(x1,x2,...,xn)为x1, x2, ..., xn的最大公约数。

输出答案对1,000,000,007取模的值。

【输入】

第一行包含3个整数,N,M,K。

第二行包含N个整数:a[1], a[2], ..., a[N]。

【输出】

输出M个整数到一行,第i个整数为当d=i时满足条件的不同数列{b[n]}的数目mod 1,000,000,007的值。

【输入输出样例1】

gcd.in

3 3 3

3 3 3

gcd.out

7 1 0

【输入输出样例2】

gcd.in

3 5 3

1 2 3

gcd.out

59 3 0 1 1

【样例1解释】

当d=1,{b[n]}可以为:(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), (2, 1, 1), (2, 1, 2), (2, 2, 1)。

当d=2,{b[n]}可以为:(2, 2, 2)。

当d=3,因为{b[n]}必须要有k个数与{a[n]}不同,所以{b[n]}不能为(3, 3, 3),满足条件的一个都没有。

【数据说明】

对于30%的数据,1<=N<=20, 1<=M<=2。

对于50%的数据,1<=N,M<=1000。

对于70%的数据,1<=N,M<=10000。

对于100%的数据,1<=N,M<=300000, 1<=K<=N, 1<=a[i]<=M。

可以推出下列公式:

ans [ d ] = C(s,sum) * ([m/d]-1)^(sum-s)  *  ([m/d])^(n-sum) 

d表示公倍数,s是与原数列要相同的数的个数(即n-k),sum为在a数列中是d倍数的数的个数。

注意取模,还有阶乘的处理。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5e5+7,M=1e9+7;
int n,m,k;
ll f[N],ans[N];
int cnt[N];
ll st(ll x,ll y)
{
    ll res=1;
    while(y)
    {
        if(y&1) res=(res*x)%M;
        x=x*x%M; 
        y>>=1;
    }
    return res;
}
ll C(ll n,ll m)
{ 
    return f[m]*st(f[n],M-2)%M*st(f[m-n],M-2)%M; 
}
int main()
{
    int a;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&a);
        cnt[a]++;
    }
    f[0]=1;
    for(int i=1;i<=n;i++) 
    f[i]=f[i-1]*i%M;
    int s=n-k;
    for(int i=m;i;i--)
    {
        int sum=0;
        for(int j=i;j<=m;j+=i) 
        sum+=cnt[j];
        if(sum<s)
        {
            ans[i]=0; 
            continue; 
        }
        ans[i]=C(s,sum)*st(m/i-1,sum-s)%M*st(m/i,n-sum)%M;
        for(int j=i*2;j<=m;j+=i) 
        ans[i]=(ans[i]+M-ans[j])%M;
    }
    for(int i=1;i<m;i++) 
    printf("%lld ",ans[i]);
    printf("%lld",ans[m]);
    return 0;
}
原文地址:https://www.cnblogs.com/mgtnb/p/12329732.html