校内测6.28

Posted lcez56jsy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了校内测6.28相关的知识,希望对你有一定的参考价值。

昨天写完了T1,T2竟然忘记保存了qaq

T1:Jelly的难题1

技术图片

 技术图片

 

 技术图片

 技术图片

真.题面:

技术图片

这看起来像一个bfs,所以我们就用bfs来做就好了

对于每个是"#"的点来说,高度就是总时间-该点被蔓延到的时间+1,最后一个被蔓延到的点的时间就是总时间。

每个点被蔓延到的时间就是当前出队的点的时间+1

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int mod=19260817;
int n,m,sx,sy,hi[509][509],pi[509][509];
char ma[509][509];
int dx[4]=1,-1,0,0,dy[4]=0,0,1,-1,lx,ly;
bool vis[509][509];
struct dl
    int x,y;
    dl(int xx,int yy):x(xx),y(yy)//构造函数
;
queue <dl> q;
int read()

    char ch=getchar();
    int x=0;bool flag=0;
    while(ch<0||ch>9)
    
        if(ch==-)flag=1;
        ch=getchar();
    
    while(ch>=0&&ch<=9)
    
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    
    if(flag)x=-x;
    return x;

bool hf(int xx,int yy)

    if(vis[xx][yy])return false;
    if(ma[xx][yy]==o)return false;
    if(xx>n||xx<1||yy>m||yy<1)return false;
    return true;

void bfs()

    while(!q.empty())//一个bfs
      
        
        dl ex=q.front();
        q.pop();
        for(int i=0;i<=3;i++)
        
            int xx=ex.x,yy=ex.y;
            xx+=dx[i];yy+=dy[i];
            if(hf(xx,yy))
            
                pi[xx][yy]=pi[ex.x][ex.y]+1;
                lx=xx;ly=yy;//记录最后一个被遍历到的点
                vis[xx][yy]=1;
                q.push(dl(xx,yy));
            
        
    

int main()


    n=read();m=read();
    for(int i=1;i<=n;i++)
    
        for(int j=1;j<=m;j++)
        
            ma[i][j]=getchar();
            while(ma[i][j]!=*&&ma[i][j]!=#&&ma[i][j]!=o)ma[i][j]=getchar();//因为读入有空格,所以要处理(过滤非法字符)
            if(ma[i][j]==*)
            
                sx=i;sy=j;//记录起点
            
        
    
    vis[sx][sy]=1;
    q.push(dl(sx,sy));
    bfs();int ans=0;
    for(int i=1;i<=n;i++)
    
        for(int j=1;j<=m;j++)
         
         if(ma[i][j]==#)    
         hi[i][j]=pi[lx][ly]-(pi[i][j]-1);
          if(pi[i][j]==0)//这里原本是判断无解的,但题目没有无解情况,所以没有遍历到的点的高度就是0
          
            hi[i][j]=0;
          
          ans+=hi[i][j];
          ans=(ans+mod)%mod;
         
         
    
    printf("%d\\n%d",pi[lx][ly],ans);

T2:音乐会【二重变革】

技术图片

技术图片

技术图片

时空限制:技术图片

看到这个数据范围,显然直接交上去这个代码它会T的飞起(事实上只有10分)

所以我们要进行一番玄学思考,推理出数学的做法。

我们先分析样例,样例1的三个数的gcd是3,n=3,3*3=9,样例2的所有数的gcd是1,n=5,1*5=5

所以我们求出所有数的gcd,然后乘n,就是答案。

怎么证明?

我们看n=2的情况,这就是更相减损术。

n>2,可以视为n=2+1+1+1+....,所以每读入进来一个x,还是相当于之前用更相减损术求出来的gcd再进行一次更相减损术,所以最后还是gcd(个人证法)

_rqy的证法:

技术图片

我们再考虑空间限制。显然开数组的话,光存储x数组基本就没有其他空间了,加之一个x求完gcd之后就没有用了,所以我们可以边读入边求,每次读入的x都会覆盖掉上一个x,这样就可以大幅度的节省空间

然后就是ac了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n,x,agcd;
int gcd(const int &a,const int &b)//非递归形式,我猜大概可以省空间吧

    int m=a,k=b;
    while(k)
    
        int r=m;
        m=k;
        k=r%k;
    
    return m;

void read(int &x)//据说可以省空间的取地址的快读

    char ch=getchar();
    x=0;bool f=0;
    while(ch<0||ch>9)
    if(ch==-)f=1;ch=getchar();
    while(ch>=0&&ch<=9)
    x=(x<<3)+(x<<1)+(ch^48);
     ch=getchar();
    
    if(f)x=-x;

int main()
  
    
    read(n);
    read(x);
    agcd=x;
    for(int i=2;i<=n;i++)
    
        read(x);
        agcd=gcd(agcd,x);
        if(agcd==1)break;//节约时间
    
     printf("%d",agcd*n);
    return 0; 

T3:音乐会【道路千万条】

OI千万条,暴力第一提条,骗分不规范,爆0两行泪

技术图片

技术图片

 

 技术图片

技术图片

技术图片

真.题面还是在最后

又是bool表达式问题。

可以想到表达式的值(虽然wz说还有一道加分二叉树也是,但是没见过,不会做,没思路)

我们复习一下关于bool表达式的true与false的关系(下面用t[x]表示x为true的方案数,f[x]表示x为false的方案数)

"&":左右两边同时为真,结果为true,否则为false。t[x&y]=t[x]*t[y],f[x&y]=t[x]*f[y]+f[x]*t[y]+f[x]*f[y]

"|":左右两边只要有一边为真,表达式的值为真,只有当左右两边的值都为假的时候,表达式为假。t[x|y]=t[x]*t[y]+t[x]*f[y]+f[x]*t[y],f[x|y]=f[x]*f[y]

"^"(异或):左右两边相同为假,不同为真。t[x^y]=t[x]*f[y]+f[x]*t[y],f[x^y]=t[x]*t[y]+f[x]*f[y]。

这个题要我们求随机指定顺序的概率。爆搜顺序在大数据面前肯定会挂的。我们可以先确定最后求哪一个运算符,再递归求下一个要计算的运算符。

据water_lift说递归会炸。

所以就有了下一个思路记忆化搜索。(代码不会啊)

我们也可以搞一个区间dp,分别开两个数组,一个记录当前的字符(t或f),一个记录第i个与第i+1个字符直接的运算符,在dp时根据运算符讨论情况。(具体的式子就是上面推导的辣)

区间dp:第一层枚举区间长度,第二层枚举起点,算出终点,不断更新

考虑到在模意义下做除法,我们还得求逆元。

走这里

虽然里面讲了线性筛,但是我只会exgcd(现在连exgcd都快忘辣)

先上wz的代码(自己的还木有搞出来)

#include<bits/stdc++.h>
using namespace std;
inline int read()

   char ch=getchar();
   int x=0;bool f=0;
   while(ch<0||ch>9)
   
    if(ch==-)f=1;
    ch=getchar();
   
   while(ch>=0&&ch<=9)
   
       x=(x<<3)+(x<<1)+(ch^48);
       ch=getchar();
    
    if(f)x=-x;
    return x;   

inline char gc()//忽略无用字符 

    char c;
    do
    
        c=getchar();
     while(c== ||c==\\n||c==\\r||c==\\0||c==\\t);
    return c;

int n;
char s[501],ops[501];//s存操作数(t or f),ops存操作符(&,|,^)
long long t[501][501],f[501][501];//i到j的true方案数,false的方案数
const int mod=998244353;
pair<long long,long long> extgcd(long long a,long long b)

    if(b==0)
    
      return make_pair<long long,long long>(1,0);
    
    pair<long long,long long>rtn=extgcd(b,a%b);
    rtn.first ^=rtn.second^=rtn.first^=rtn.second;//交换两个变量 
    rtn.second-=a/b*rtn.first;
    return rtn;

int main()

    n=read();
    for(int i=1;i<=n-1;i++)
    
        s[i]=gc();
        ops[i]=gc();
    
    s[n]=gc();
    for(int i=1;i<=n;i++)//初始化 
    
        if(s[i]==t)
          t[i][i]=1,f[i][i]=0;
        else
          f[i][i]=1,t[i][i]=0;
    
    for(int len=2;len<=n;len++)//区间dp枚举区间长 
    
        for(int i=1;i+len-1<=n;i++)//枚举起点 
        
            int j=i+len-1;//计算终点
             for(int k=i;k<j;k++)//枚举断点
              
               if(ops[k]==&)
                
                  t[i][j]=(t[i][j]+(t[i][k]*t[k+1][j])%mod)%mod;//为‘&‘,true为左右两边都必须是true 
                  f[i][j]=(f[i][j]+(f[i][k]*f[k+1][j])%mod+(t[i][k]*f[k+1][j])%mod+(f[i][k]*t[k+1][j])%mod)%mod;
                 //false:左右都是false,左false右true,左true右false 
                
                if(ops[k]==|)
                
                  t[i][j]=(t[i][j]+(t[i][k]*t[k+1][j])%mod+(t[i][k]*f[k+1][j])%mod+(f[i][k]*t[k+1][j])%mod)%mod;    
                  //true:两端true,左true右false,左false右true 
                  f[i][j]=(f[i][j]+(f[i][k]*f[k+1][j])%mod)%mod;
                  //false:两端都false 
                
                if(ops[k]==^)
                
                    t[i][j]=(t[i][j]+(t[i][k]*f[k+1][j])%mod+(f[i][k]*t[k+1][j])%mod)%mod;
                    //true:左false右true,左true右false(两端不同) 
                    f[i][j]=(f[i][j]+(t[i][k]*t[k+1][j])%mod+(f[i][k]*f[k+1][j])%mod)%mod;
                    //false:左true右true,左false右false(两边不同) 
                    
              
            
        
    
    cout<< (t[1][n] * ((extgcd(t[1][n] +f[1][n] %mod, mod).first%mod+mod) %mod)) %mod<<endl;//t(1,n)/(t(1,n)+f(1,n)) % mod

 

以上是关于校内测6.28的主要内容,如果未能解决你的问题,请参考以下文章

10步搞定App内测发布(蒲公英内测平台)

应用内测分发详细攻略

应用内测分发详细攻略

应用内测分发详细攻略

iOS微信内测版本最新内测,需要先申请

微信应用号邀请码申请,小程序内测资格