校内测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
}

原文地址:https://www.cnblogs.com/lcez56jsy/p/11105752.html

时间: 2024-10-26 22:20:04

校内测6.28的相关文章

湖南多校对抗赛3.28 J - Jerry&#39;s trouble

Problem J: Jerry's trouble Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 96  Solved: 46 [Submit][Status][Web Board] Description Jerry is caught by Tom. He was penned up in one room with a door, which only can be opened by its code. The code is the

2017-8-31 NOIP模拟赛(校内测)

可接受序列 [题目描述] 让计算机这样读入一列非负整数: 1.读入数T. 2.接着往下读入T个数. 3.如果数列读完了,则停止,否则,转到1. 但是,往往会出现这样的问题:执行第2步时,数列已经没有T个数了.如果这样,我们称这个数列是“不可接受的”,否则,称它是“可接受的”.我们需要用最少的步数把一个数列变成“可接受的”,一步是指: 1.把数列中的某一个数加1. 2.把数列中的某一个数减1. [输入格式] 第一行有一个数N (1<=N<=1000000),表示数列的长度,接下来有n行,描述这个

酱油记:校内测DAY1-morning

为了给我们这些蒟蒻一点简(ju)单(nan)的考验,这段时间来了套联测(2017.11.6~2017.11.9) DAY1-morning 蒟蒻世界: T1:做的时候第一道题一开始没看清题意,后来发现其实就是求最少分成多少个段,使得每个段都呈不上升或不下降的序列,我做的时候,就想着,直接做嘛,先做差,然后就直接遍历一遍,一旦有不符合当前的不上升或不下降的话,ans++,结果只拿了90 T2:接下来打完就去打第二题了,就是给出一个环(环上的数为1到n),有两种操作,一种顺时针或逆时针旋转环,另一种

工大助手--加权平均分计算

工大助手--加权平均分计算 实现功能 1)用户可选择获取入学以来所有已修课程的相关信息:课程代号.课程名.课程属性.学分.成绩等信息. 2)用户可选择获取特定已修课程的相关信息:课程代号.课程名.课程属性.学分.成绩等信息. 3)用户可获得特定时间段内的加权平均分(1学期.1学年.全部). 团队成员 13070003 张   帆 13070046 孙宇辰 13070004 崔   巍 13070006 王   奈 13070002 张雨帆 13070045 汪天米 加权平均分计算 在计算加权平均

【前方高能】!后效性!

今天校内测 由于忽视了后效性的问题,很happy地爆炸了 然后就华华丽丽地炸掉了树形dp..AK→220 然后悲剧的想到因为没有消掉后效性而炸掉的dp题好像不是第一个了QAQ 所以这波就讲关于dp中消除后效性的问题 dp中有一个很重要的问题就要保证无后效性,在状态转移的过程中非常关键 简单说,后效性就是之后要求的决策不会对当前要求决策产生干扰 所以如果没有处理好后效性的问题,dp很有可能就是白写了 比较常见的就是迭代之类的问题 ,,今天就是在迭代的时候崩掉的 就以这题为例↓ 3.Nearby C

Windows7WithSP1/TeamFoundationServer2012update4/SQLServer2012

[Info   @09:03:33.737] ====================================================================[Info   @09:03:33.743] Team Foundation Server Administration Log[Info   @09:03:33.748] Version  : 11.0.61030.0[Info   @09:03:33.748] DateTime : 05/24/2014 17:0

2014/4/28 多校第九次

C:快速求N以内因数和,N以内互质数的和. 容斥版: 1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define maxn 1100000 5 #define LL long long 6 //N以内gcd(i,N)==1的i的和 7 using namespace std; 8 bool flag[maxn]; 9 int prim[maxn/3],cnt; 10 int pri

HDU 5344 MZL&#39;s xor (多校)[补7月28]

MZL's xor Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 249    Accepted Submission(s): 187 Problem Description MZL loves xor very much.Now he gets an array A.The length of A is n.He wants to k

6.3.28微信需群主确认才可进群&amp;发GIF动图功能内测开始了

昨天下午有网友收到微信6.3.28新版内测邀请,不过这个内部体验目前貌似只对安卓手机开放,苹果的IOS系统还不支持,会提示“你当前使用的是非安卓设备,不建议下载安卓体验包,但你仍可邀请朋友尝鲜”.最新安卓微信内测版主要的新功能是1.群主可启用需群主确认才可邀请朋友进群功能.2.聊天可以发送GIF动图 1.群主可启用需群主确认才可邀请朋友进群功能. 哎哟喂,多出这么个功能,以后对于微信管理群那是要多方便啊,再也不操心别人乱拉人进群,这个对于成员的甄别得到的大大的保证,也不怕说那些三更半夜或者是忙时