11.30 模拟赛

11.30 模拟赛

T1

题面

​ 在一场奇怪的梦里,小Y来到了一个神奇的国度。这个国度可以用一根数轴表示,小Y在\(N\)处,而小Y想吃的美食在\(K\)处。

​ 小Y有两种方式移动,一种叫做步行,一种叫做瞬移。对于每次步行操作,小Y可以从\(x\)移动到\(x+1\)或者\(x-1\),而对于每次瞬移操作小Y可以从\(x\)瞬移到\(2x\)。那么小Y最少要移动多少次才能到达\(K\)处吃到食物呢?

【数据范围】\(0\le N,K\le 100,000\)

题解

水题。只需要bfs计算每个点的最短路程即可。首先不可能走到负数点(一定不需要);其次不可能走到超过2e5的点(更多的一定会远离),因此可以确定较紧的边界\([0,200000]\)


思考:4min 实现:10min;

预计100 实际:90

没看到小于等于,边界设定为了\(>0\),结果挂了第三个点(\(N=100000,K=0\)

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=200009,INF=0x3f3f3f3f;
typedef pair<int,int> P;
int n,k,f[N];
bool v[N];
int main(){
    freopen("meet.in","r",stdin);
    freopen("meet.out","w",stdout);
    scanf("%d%d",&n,&k);
    memset(f,INF,sizeof(f));
    queue<P> que;
    que.push(make_pair(n,0));
    while(!que.empty()){
        P now=que.front();
        que.pop();
        int pos=now.first,val=now.second;
        //cout<<pos<<endl; 
        v[pos]=true;
        f[pos]=min(f[pos],val);
        /*WA: pos-1>0*/
        if(pos-1>=0&&pos-1<N&&!v[pos-1]) 
            que.push(make_pair(pos-1,val+1));
        if(pos+1>=0&&pos+1<N&&!v[pos+1]) 
            que.push(make_pair(pos+1,val+1));
        if(pos*2>=0&&pos*2<N&&!v[pos*2]) 
            que.push(make_pair(pos*2,val+1));
    }
    cout<<f[k]<<endl;
    return 0;
}

T2

题面

给定长度为\(n\)的序列\(a_1,\dots,a_n\),定义一次操作为:

  1. 定义序列\(S\)\(a\)的前缀和;
  2. \(S\)复制回\(a\)

给定整数\(k\),求对\(a\)进行\(k\)此操作后的序列,对\(10^9+7\)取模。

题解

Subtask:

1~8 暴力

1~20 矩阵快速幂+对称性优化

19~22 每次操作的系数在杨辉三角中右下移一格 组合数表示即可

正解:

操作后序列每一项都是由前\(i\)个数乘上系数之和,而系数正好就是\(a[i]=1\)中答案序列倒过来

因此只要在19~22上加权即可

如果直接每次算组合数会超时,所以需要用前一项来推有一项


看了5分钟觉得应该就是考虑每一项对总答案的贡献系数,所以想到\(a_i\)是由\(a_1,a_2,\dots,a_i\)乘上系数起来的就可以了。实际做的时候发现这个系数很难求,当时想的是高阶等差数列,但是又没有求和公式,所以就不会做了

其实系数的规律已经发现了 只需要看到是组合数而不只是高阶等差数列就A掉了)

最后写了个递推暴力 过了8个点(\(f[i][j]=f[i-1][j]+f[i][j-1]\)

还在想是不是需要优化这个递推过程

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5009,K=1009,P=1e9+7;
typedef long long ll;
ll n,k,a[N];
ll b[N],c[N]; //b记录答案,c记录系数
void input(){
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
}
ll qpow(ll x,ll y){
    ll res=1,tmp=x;
    while(y){
        if(y&1) res=(res*tmp)%P;
        tmp=(tmp*tmp)%P;
        y>>=1;
    }
    return res;
}
void solve(){
    //for(int i=1;i<=n;i++)
       // c[i]=C(i-1,k+i-2);
    //原来的C(x,y)用于计算组合数,但会超时,因此改为递推
    c[1]=1;
    for(int i=2;i<=n;i++)
        c[i]=(((c[i-1]*(k+i-2))%P)*qpow(i-1,P-2))%P;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
            b[i]=(b[i]+a[j]*c[i-j+1])%P;
    for(int i=1;i<=n;i++)
        printf("%d ",b[i]);
}
int main(){
    freopen("sum.in","r",stdin);
    freopen("sum.out","w",stdout);
    input();
    /*if(k<=1000) solvedp();
    else*/ solve();
    return 0;
}

T3

题面

​ 恋之微风·小乔,是手游《王者荣耀》中的法师型英雄,擅长远程消耗。小乔有一把神奇的扇子,借助灵活的走位可以对敌人造成高额的伤害。小乔是小 A 最喜欢(会玩)的英雄之一。在一场梦里,小 A 与小乔来到了一个异次元世界。

​ 异次元世界位于极坐标系中。小乔定义了一个值\(m\),以等分\([-\pi,\pi]\)弧度。小乔利用她神奇的扇子,进行\(n\)次“绽放之舞“操作。对于第\(i\)次“绽 放之舞”操作,小乔将设定半径\(r_i\),起始位置\(s_i\),终止位置\(t_i\),她借助自己神奇 的扇子,以坐标系原点为圆心,\(r_i\)为半径,将圆心角\(\dfrac{\pi s_i}{m}\)到圆心角\(\dfrac{\pi t_i}{m}\)这部分扇形区域逆时针叠加一层“治愈微笑”。

​ 小乔想到了一个有趣(奇怪)的问题,她希望知道有多大面积的区域被叠加 过至少\(k\)层“治愈微笑”。这个问题难倒了平日里善于发现并解决问题的小 A,现 在小 A 求助于你,希望你能帮他解决这个问题。

​ 我们设答案的值为\(T\),为了方便表达,你只需要输出\(T\cdot \dfrac{2m}{\pi}\)(可以证明这是 一个非负整数)的值即可。

题解

将扇形的起始边和结束边排序,将圆周分成\(O(n)\)个部分。考虑一个区间时,将覆盖此区间的所有扇形取出,求出第\(k\)大的扇形,其覆盖面积就是符合条件的面积(因为较大的扇形一定覆盖较小的梯形)。

支持查询第\(k\)大数并可以插入和删除的数据结构我选用的是BIT(平衡树也可以)

需要注意\(t_i\)可能小于\(s_i\)


一开始想的是扫描线 但是想不清楚

然后就去写了暴力和差分的部分分 结果差分写挂了

订正的时候因为C++不知道什么诡异的判定机制调了好久

包括但不仅限于node(6行)里面的int改成ll就挂;在添加节点(35行)时如果不用tmp就会判定错误等等等等)

后面发现是在改ll的时候忘了把%d改成%lld了……

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=200009;
typedef long long ll;
ll n,m,k,r[N],s[N],t[N],bit[N<<1];
struct node{
    ll p,v,r; //pos,val(-1/1),radius
    bool operator < (const node &a)const{
        return p<a.p;
    }
} h[N<<1];
void input(){
    cin>>n>>m>>k;
    for(ll i=1;i<=n;i++)
        scanf("%lld%lld%lld",&r[i],&s[i],&t[i]);
}
void upd(ll pos,ll val){
    while(pos<=N){
        bit[pos]+=val;
        pos+=(pos&-pos);
    }
}
ll query(ll pos){
    ll res=0;
    while(pos){
        res+=bit[pos];
        pos-=(pos&-pos);
    }
    return res;
}
void solve(){
    for(ll i=1;i<=n;i++)
        s[i]+=m+1,t[i]+=m+1;
    int tot=0;
    for(ll i=1;i<=n;i++){
    	int tmp=s[i]-t[i];
        if(tmp<0){
            h[++tot]=(node){s[i],1,r[i]};
			h[++tot]=(node){t[i],-1,r[i]};
		}
        else{
            h[++tot]=(node){1,1,r[i]};
			h[++tot]=(node){t[i],-1,r[i]};
            h[++tot]=(node){s[i],1,r[i]};
			h[++tot]=(node){2*m+1,-1,r[i]};
        }
    }
    sort(h+1,h+tot+1);
    ll ans=0,cnt=0;
    for(ll i=1;i<=tot-1;i++){
        upd(h[i].r,h[i].v);
        cnt+=h[i].v;
        if(cnt<k) continue;
        ll l=1,r=N-1;
        while(l!=r){
            ll mid=(l+r)>>1;
            ll tmp=cnt-query(mid)+1;
            if(tmp>k) l=mid+1;
            else r=mid;
        }
        ans+=l*(h[i+1].p-h[i].p)*l;
    }
    cout<<ans<<endl;
}
int main(){
    freopen("xiaoqiao.in","r",stdin);
    freopen("xiaoqiao.out","w",stdout);
    input();
    /*if(n<=100) solveBF();
    else solveT();*/
    solve();
    return 0;
}
posted @ 2020-12-01 09:54  Cander花朵  阅读(74)  评论(0编辑  收藏  举报