牛客小白月赛17-记录(附题解)

正题

比赛链接:https://ac.nowcoder.com/acm/contest/1085#question


成绩

在这里插入图片描述在这里插入图片描述


总结

除了那道积分数学其他还好

后面没有 F F F题的题解


T 1 : 小 s u n 的 假 期 T1:小sun的假期 T1:sun

题目大意

长度为 n n n的序列, m m m个区间,求最大的没有被任何区间覆盖的区间。

解题思路

我们将区间按照右端点从大到小枚举,我们每次求从这个右端点往右可以扩展多少格。我们会发现只有右端点在它右边的会造成影响。而这个值就是这些区间最左的左端点。

c o d e code code

#include
#include
#include
using namespace std;
const int N=1e5+100;
struct node{
    int l,r;
}a[N];
int n,m,ans,Min;
bool cMp(node x,node y)
{return x.r<y.r;}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&a[i].l,&a[i].r);
    sort(a+1,a+1+m,cMp);Min=n;
    for(int i=m;i>=1;i--){
        ans=max(ans,Min-a[i].r);
        Min=min(Min,a[i].l);
    }
    printf("%d",ans);
}

T 2 : T2: T2:扫雷

题目大意

n ∗ m n*m nm的图,有一些雷,求每个位置旁边有多少雷

解题思路

暴力模拟不解释

c o d e code code

#include
#include
#include
using namespace std;
int a[1002][1002],n,m;
int main()
{
    //freopen("mine.in","r",stdin);
    //freopen("mine.out","w",stdout);
    scanf("%d%d\n",&n,&m);
    string s;
    for (int x=1;x<=n;x++)
    {
        getline(cin,s);
        for (int y=0;y<m;y++)
        {
            if (s[y]=='*')
            {
                for (int i=x-1;i<=x+1;i++)
                  for (int j=y-1;j<=y+1;j++)
                  {
                    if (i>=0 && j>=0 && i<=n && j<=m && a[i][j+1]!=23333)
                      a[i][j+1]++;
                  }
                  a[x][y+1]=23333;
            }
        }
    }
    for (int i=1;i<=n;i++)
    {
      for (int j=1;j<=m;j++)
        if (a[i][j]==23333) printf("%c",'*');
        else printf("%d",a[i][j]);
      printf("\n");
    }
}

T 3 : T3: T3: 异或和

题目大意

n n n个数,求出现次数为奇数的数异或和

解题思路

若出现次数为偶数,两两异或抵消,所以就是求所有数的异或和

c o d e code code

#include
#include
#include
using namespace std;
int n,a,ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a),ans^=a ;
    printf("%d",ans);
}

T 4 : T4: T4:解密

题目大意

加密方法是将字符串每个字符 c c c变为 ( k 1 ∗ c + k 2 ) % 26 (k1*c+k2)\%26 (k1c+k2)%26。给一串加密后的,要求解密。

解题思路

暴力枚举解密后的,然后匹配即可。

c o d e code code

#include
#include
#include
#define ll long long
using namespace std;
ll k1,k2,big,a,n;
char s[1100];
int main()
{
    scanf("%lld%lld",&k1,&k2);
    scanf("%s",s+1);n=strlen(s+1);
    for(ll i=1;i<=n;i++){
        big=(s[i]<='Z');
        a=s[i]-(s[i]<='Z'?'A':'a');
        for(ll j=0;j<=25;j++)
            if((j*k1+k2)%26ll==a)
            {printf("%c",j+(big?'A':'a'));break;}
    }
}

T 5 : T5: T5:图的遍历

题目大意

一张无向图,每次走两步,求至少增加多少条边可以遍历完整张图

解题思路

考虑贪心,我们先考虑现在的图联通,我们可以将图分为偶点和奇点。偶点就是可以遍历到的,奇点就是不能的,我们发现若有奇点此时答案为1,否则为0.

那若是分为若干个联通块呢?我们会发现联通块之间无论如何连接并不会影响答案,所以直接暴力连接即可。

c o d e code code

#include
#include
#include
using namespace std;
const int N=1e5+100;
struct node{
    int to,next;
}a[N*2];
int n,m,ls[N],tot,ans,z,last;
bool v[N][2];
void addl(int x,int y)
{
    a[++tot].to=y;
    a[tot].next=ls[x];
    ls[x]=tot;
}
void dfs(int x,int k)
{
    if(v[x][k]) return;
    v[x][k]=1;
    for(int i=ls[x];i;i=a[i].next)
        dfs(a[i].to,k^1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        addl(x,y);addl(y,x);
    }
    last=1;dfs(1,1);
    for(int i=2;i<=n;i++)
        if(!v[i][0]&&!v[i][1])
        {ans++;dfs(i,1);addl(last,i);last=i;}
    memset(v,0,sizeof(v));
    dfs(1,1);
    for(int i=1;i<=n;i++)
        if(!v[i][1])
        {ans++;break;}
    printf("%d",ans+z);
}

T 7 : T7: T7:区间求和

题目大意

一个序列,每次询问一个区间 [ l , r ] [l,r] [l,r]
∑ i = l r a i ∗ n u m ( a i ) \sum_{i=l}^r a_i*num(a_i) i=lrainum(ai)
n u m ( a i ) num(a_i) num(ai)表示这个区间中 a i a_i ai的数量

解题思路

显然的莫队不解释。

c o d e code code

#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
%:pragma GCC optimize("-fgcse")
%:pragma GCC optimize("-fgcse-lm")
%:pragma GCC optimize("-fipa-sra")
%:pragma GCC optimize("-ftree-pre")
%:pragma GCC optimize("-ftree-vrp")
%:pragma GCC optimize("-fpeephole2")
%:pragma GCC optimize("-ffast-math")
%:pragma GCC optimize("-fsched-spec")
%:pragma GCC optimize("unroll-loops")
%:pragma GCC optimize("-falign-jumps")
%:pragma GCC optimize("-falign-loops")
%:pragma GCC optimize("-falign-labels")
%:pragma GCC optimize("-fdevirtualize")
%:pragma GCC optimize("-fcaller-saves")
%:pragma GCC optimize("-fcrossjumping")
%:pragma GCC optimize("-fthread-jumps")
%:pragma GCC optimize("-funroll-loops")
%:pragma GCC optimize("-fwhole-program")
%:pragma GCC optimize("-freorder-blocks")
%:pragma GCC optimize("-fschedule-insns")
%:pragma GCC optimize("inline-functions")
%:pragma GCC optimize("-ftree-tail-merge")
%:pragma GCC optimize("-fschedule-insns2")
%:pragma GCC optimize("-fstrict-aliasing")
%:pragma GCC optimize("-fstrict-overflow")
%:pragma GCC optimize("-falign-functions")
%:pragma GCC optimize("-fcse-skip-blocks")
%:pragma GCC optimize("-fcse-follow-jumps")
%:pragma GCC optimize("-fsched-interblock")
%:pragma GCC optimize("-fpartial-inlining")
%:pragma GCC optimize("no-stack-protector")
%:pragma GCC optimize("-freorder-functions")
%:pragma GCC optimize("-findirect-inlining")
%:pragma GCC optimize("-fhoist-adjacent-loads")
%:pragma GCC optimize("-frerun-cse-after-loop")
%:pragma GCC optimize("inline-small-functions")
%:pragma GCC optimize("-finline-small-functions")
%:pragma GCC optimize("-ftree-switch-conversion")
%:pragma GCC optimize("-foptimize-sibling-calls")
%:pragma GCC optimize("-fexpensive-optimizations")
%:pragma GCC optimize("-funsafe-loop-optimizations")
%:pragma GCC optimize("inline-functions-called-once")
%:pragma GCC optimize("-fdelete-null-pointer-checks")
#include
#include
#include
#include
#define ll long long
using namespace std;
const int N=1e5+100;
struct node{
    ll l,r,id,pos;
}a[N];
ll n,m,w[N],l,r,now,id[N],t;
ll cnt[N],ans[N];
bool operator <(node x, node y) {
    return x.pos<y.pos||(x.pos==y.pos&&x.r<y.r);
}
inline ll read() {
    ll x=0,f=1; char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x*f;
}
void print(ll x){
    if (x>9) print(x/10); putchar(x%10+48); return;
}
void add(ll x)
{now+=(2*cnt[x]+1)*x;cnt[x]++;}
void del(ll x)
{now-=(2*cnt[x]-1)*x;cnt[x]--;}
int main()
{
    n=read();m=read();t=sqrt(n);
    for(ll i=1;i<=n;i++)
      w[i]=read();
    for(ll i=1;i<=m;i++)
        a[i].l=read(),a[i].r=read(),a[i].id=i,a[i].pos=(a[i].l-1)/t+1;
    sort(a+1,a+1+m);
    l=1,r=0;
    for(ll i=1;i<=m;i++)
    {
        while(l>a[i].l) add(w[--l]);
        while(r<a[i].r) add(w[++r]);
        while(l<a[i].l) del(w[l++]);
        while(r>a[i].r) del(w[r--]);
        ans[a[i].id]=now;
    }
    for(ll i=1;i<=m;i++)
        print(ans[i]),putchar('\n');
}

T 8 : T8: T8:取球游戏

题目大意

c c c种颜色,抽随机 n n n个(每种颜色等概率),求最后是 m m m种颜色个数为奇数的概率

解题思路

我们设 f i , j f_{i,j} fi,j表示抽到第 i i i个,颜色为 j j j个的方案数,有
f i , j ∗ j c     + >     f i + 1 , j − 1 f_{i,j}*\frac{j}{c}\ \ \ +>\ \ \ f_{i+1,j-1} fi,jcj   +>   fi+1,j1
f i , j ∗ c − j c     + >     f i + 1 , j + 1 f_{i,j}*\frac{c-j}{c}\ \ \ +>\ \ \ f_{i+1,j+1} fi,jccj   +>   fi+1,j+1

这个可以用矩阵乘法优化即可。

c o d e code code

#include
#include
#include
#define ll long long
using namespace std;
const ll Size=111;
ll n,c,m;
double a[Size][Size],ans[Size][Size],C[Size][Size];
void mulself() {
    for(ll i=0;i<=c;i++)
        for(ll j=0;j<=c;j++)
            C[i][j]=0;
    for(ll i=0;i<=c;i++)
        for(ll j=0;j<=c;j++)
            for(ll k=0;k<=c;k++)
                C[i][j]+=a[i][k]*a[k][j];
    for(ll i=0;i<=c;i++)
        for(ll j=0;j<=c;j++)
            a[i][j]=C[i][j];
}
void mul(){
    for(ll i=0;i<=c;i++)
        for(ll j=0;j<=c;j++)
            C[i][j]=0;
    for(ll i=0;i<=c;i++)
        for(ll j=0;j<=c;j++)
            for(ll k=0;k<=c;k++)
                C[i][j]+=a[i][k]*ans[k][j];
    for(ll i=0;i<=c;i++)
        for(ll j=0;j<=c;j++)
            ans[i][j]=C[i][j];
}
void ksm(ll b) {
    while(b)
    {
        if(b&1) mul();
        mulself();
        b>>=1;
    }
}
int main()
{
    scanf("%lld%lld%lld",&c,&n,&m);
    a[0][1]=1;a[c][c-1]=1;
    for(ll i=1;i<c;i++)
        a[i][i+1]=(double)(c-i)/c,a[i][i-1]=(double)i/c;
    for(ll i=0;i<=c;i++)
        ans[i][i]=1;
    ksm(n);
    printf("%.3lf",ans[0][m]);
}

T 9 : T9: T9:坐电梯

题目大意

m m m个请求楼层,优先走到最高层的,求要多久才接到 k k k

解题思路

在所有读入的数中求一个最大值 h h h,然后答案就是 2 h − 1 − k 2h-1-k 2h1k

c o d e code code

#include
#include
#include
using namespace std;
int n,k,maxs,num;
int main()
{
    scanf("%d%d",&n,&k);
    maxs=k;
    for(int i=1;i<=n;i++){
        scanf("%d",&num);
        maxs=max(maxs,num);
    }
    printf("%d",maxs-1+maxs-k);
}

T 10 : T10: T10:技术

题目大意

一序列中有的空缺了,求有多少种填数方式使得这是一个单调不降序列

解题思路

我们发现若一段连续的空缺 l l l,且这段空缺中可以填的数的个数为 k k k,那么这段空缺的方案数就是 C k + l − 1 l − 1 C^{l-1}_{k+l-1} Ck+l1l1(插板法)。然后计算方案数即可。

c o d e code code

#include
#include
#include
#define ll long long
using namespace std;
const ll XJQ=1e9+7,N=2e6+100;
ll num[N],n,ans=1,last=1000,z,inv[N];
ll C(ll n,ll m)
{
    if(n<m) return 0;
    ll ans=1;
    for(ll i=1;i<=m;i++)
        ans=ans*((n-i+1)%XJQ)%XJQ*inv[i]%XJQ;
    return ans;
}
int main()
{
    scanf("%lld",&n);
    inv[1]=1;
    for(ll i=2;i<=N;i++)
        inv[i]=inv[XJQ%i]*(XJQ-XJQ/i)%XJQ;
    for(ll i=1;i<=n;i++){
        scanf("%lld",&num[i]);
        if(num[i]){
            (ans*=C(last-num[i]+i-z-1,i-z-1))%=XJQ;
            last=num[i];z=i;
        }
    }
    (ans*=C(last-1+n-z,n-z))%=XJQ;
    printf("%lld",ans);
}

你可能感兴趣的:(模拟赛)