zoukankan      html  css  js  c++  java
  • 11.4 模拟赛

    这分数羞于出口(fuck)

    T1 大空魔术

    题目:

    宇佐见莲子是一个向往太空旅行的大学生。但迫于月面旅行团高额的费用,她暂时放弃了幻想,开

    始专心于物理学的研究。

    在一次偶然的经历中,莲子发现了两种新的粒子,她将这两种粒子命名为「粒子 A」和「粒子 B」 。

    莲子发现,两种粒子在不受外界刺激的情况下可以保持稳态,并且会相互吸引。多个粒子在相互的

    吸引力作用下会形成一个有序的序列。

    莲子还发现,当特定种类的两个粒子以特定方式排列时,给予它们一种特定的刺激,就会发生「互

    毁」现象:两个粒子会发生完全的物质-能量转换,转化为大量能量。

    经过长时间的研究,莲子发现了「互毁」现象发生的条件:当前仅当相邻的两个粒子呈现:”AB”

    或”BB” 的形式时,给予特定刺激后它们才会发生「互毁」 。

    现在,莲子在实验室中将众多粒子排成了多个序列,她想通过给予刺激的方式,用这些粒子得到尽

    可能多的能量,即留下尽可能少的粒子。

    由于粒子会相互吸引,每当相邻的两个粒子发生「互毁」后,它们左右两侧的粒子还会拼在一起,

    仍然保持一个序列的形态。

    但粒子数实在是太多了,于是她找到你,请你帮助她求出最后剩余粒子数的最小值。

    输入:

    第 1 行一个整数 t,代表粒子序列的个数。

    第 2∼ t 行,第 i + 1 行包含一个只由字符 'A' 和 'B' 构成的字符串 (s_i) ,描述了一个粒子序列。

    输出:

    一个整数,代表最后剩余粒子数

    样例:

    3

    AAA

    BABA

    AABBBABBBB

    3

    2

    0

    解题思路:

    对于这个有序序列,我们能删就删,尽管有 ABBA这种情况,我们发现会有 两种删法,但是它产生的贡献却都是一样的,都是 2,所以我们可以根据这个贪心,枚举子串,### 利用一下栈,然后碰上A就入栈,碰上B就出栈,因为无论什么情况,造成出栈的一定是有B的子串,所以枚举到最后只需要看一下还剩下多少就OK了,

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <cstdlib>
    #define inf 0x3f
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){ if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    std::stack<char> s; 
    int main()
    {
    	int t=read();
    	while(t--)
    	{
    		std::string ch;
    		std::cin>>ch;
    		for(int i=0;i<=ch.length();i++)
    		{
    			if(ch[i]=='A')
    			{
    				s.push(ch[i]);
    				continue;
    			}
    			else if(ch[i]=='B')
    			{
    				if(s.empty()) 
    				{
    					s.push(ch[i]);
    				}
    				else 
    				{
    					//char top=s.top();
    					s.pop();	
    				}	
    			}
    		}
    		printf("%d
    ",s.size());
    	}
    	return 0;
    }
    

    T2 夜桜街道

    题目描述:

    深夜,离开实验室后,莲子与好友梅丽相约来到了一条长满樱花树的街道,她们决定从街道的左侧

    某个位置出发向右走,欣赏沿途的每一棵樱花。

    她们发现,这条街道上共有 n 棵樱花树,从左到右的编号依次为 1,2,···n,每一棵樱花树都有自

    己的美丽值,编号为 i 的樱花树的美丽值为(a_i)

    莲子喜欢惊喜的感觉。若她以某个位置作为起点向右走,她看到一棵樱花树的惊喜度定义为:从起

    点到这棵树途经的所有树中,比这棵树的美丽值小的个数。

    梅丽决定用平均值描述莲子的平均惊喜度。她定义区间 [l,r] 的平均惊喜度为,从樱花树 l 开始走,

    向右走到樱花树 r 时,看到所有樱花树的惊喜度之和,除以区间中樱花树的个数。

    现在,莲子和梅丽想知道,以樱花树 1 为起点,分别以樱花树 1 ∼ n 为终点时,莲子的平均惊喜

    度之和。

    由于她俩都不喜欢小数,你只需要输出这个值对 998244353 取模的结果。

    输入:

    第 1 行一个整数 n,表示樱花树的棵树。

    第 2 行有 n 个整数,第 i 个整数表示编号为 i 的樱花树的美丽值(a_i)

    输出:

    一行一个整数,表示答案。

    样例:

    6

    1 1 4 5 1 4

    748683269

    数据:

    对于测试点 1 ∼ 6 ,保证 n ≤ 1000。

    对于测试点 1 ∼ 10,保证 n ≤ 5000。

    对于测试点 1 ∼ 20,保证 n ≤(10^6)

    对于所有测试点,保证 n ≤(10^6) ,0 ≤(a_i)(2^{30}-1)

    解题思路:

    我们输入每个(a_i)的时候我们可以用树状数组去维护一下它前面的比它小的数,怎么统计,我们就可以考虑权值树状数组,但是数据开不了,所以需要离散化一下,然后在,如果

    离散化的话,就求个顺序对,然后,再利用逆元,求解就行了。

    代码:

    未进行离散化的

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <cstdlib>
    #define inf 0x3f
    #define lowbit(x) x&(-x)
    #define int long long
    const int maxn=1e6;
    const int mod=998244353;
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){ if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    int n; 
    int num[maxn],s[maxn],tree[maxn],inv[maxn];
    int MAX;
    void add(int x,int k)
    {
    	for(int i=x;i<=MAX;i+=lowbit(i))
    	{
    		tree[i]++;
    	}
    }
    int find(int x)
    {
    	int sum=0;
    	for(int i=x;i>=1;i-=lowbit(i))
    	{
    		sum+=tree[i];
    	}
    	return sum;
    }
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		num[i]=read();
    		MAX=std::max(MAX,num[i]);
    	}
    	for (int i = 1; i <= n; i++)
    	{
    		s[i]=find(num[i]-1);//小于等于的为 find(num[i]), 
    		//std::cout<<s[i]<<"TEXT"<<std::endl;
    		add(num[i],1);
    	}
    	int ans=0;
    	inv[1]=1;
    	/*for(int i=1;i<=n;i++)
    	{
    		// -k * r_-1
    		inv[i]=(-p/i)*inv[p%i];
    	} */
    	for(int i=2;i<=n;i++)
    	{
    		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		s[i]+=s[i-1];
    		s[i]%=mod;
    		ans=(ans+inv[i]%mod*s[i])%mod;
    		ans%=mod;
    //		std::cout<<inv[i]<<std::endl;
    //		std::cout<<ans<<std::endl;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

    进行了离散化的

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <cstdlib>
    #define inf 0x3f
    #define lowbit(x) x&(-x)
    #define int long long
    const int maxn=1e6;
    const int mod=998244353;
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){ if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    int n; 
    int num[maxn],s[maxn],tree[maxn],inv[maxn];
    int MAX;
    void add(int x,int k)
    {
    	for(int i=x;i<=MAX;i+=lowbit(i))
    	{
    		tree[i]++;
    	}
    }
    int find(int x)
    {
    	int sum=0;
    	for(int i=x;i>=1;i-=lowbit(i))
    	{
    		sum+=tree[i];
    	}
    	return sum;
    }
    int b[maxn];//离散化用的数组 
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		num[i]=read();
    		b[i]=num[i];
    		MAX=std::max(MAX,num[i]);
    	}
    	std::sort(b+1,b+n+1);//从小到大排序
    	int len = std::unique(b+1,b+n+1)-b-1; 
    	for(int i=1;i<=n;i++)
    	{
    		num[i]=std::lower_bound(b+1,b+len+1,num[i])-b;
    		MAX=std::lower_bound(b+1,b+len+1,MAX)-b;
    	}
    	for (int i = 1; i <= n; i++)
    	{
    		s[i]=find(num[i]-1);//小于等于的为 find(num[i]), 
    		//std::cout<<s[i]<<"TEXT"<<std::endl;
    		add(num[i],1);
    	}
    	int ans=0;
    	inv[1]=1;
    	/*for(int i=1;i<=n;i++)
    	{
    		// -k * r_-1
    		inv[i]=(-p/i)*inv[p%i];
    	} */
    	for(int i=2;i<=n;i++)
    	{
    		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		s[i]+=s[i-1];
    		s[i]%=mod;
    		ans=(ans+inv[i]%mod*s[i])%mod;
    		ans%=mod;
    //		std::cout<<inv[i]<<std::endl;
    //		std::cout<<ans<<std::endl;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    

    T3科学世纪

    问题描述:

    t 组数据,每次给定整数 p,q,求一个最大的整数 x,满足 p 可以被 x

    整除,并且 q 不能整除 x。

    输入:

    第 1 行一个整数 t,代表数据组数。

    第 2 ∼ t + 1 行,每行两个整数 p,q,代表给定的两个参数。

    输出:

    共 t 行,每一行代表对应的 x 的值。

    样例:

    输入:

    3

    10 4

    12 6

    179 822

    输出:

    10

    4

    179


    思路分析:

    显然,如果 (p<q),那么(p|x)的时候,(p ot|x),很显然,(p)就符合输出的条件,那么我们这个时候输出p 就好了,同时,(p) % (q) !=0的时候,也就输出(p)就好了,

    那现在就是考虑其他情况的时候,我们考虑一下,(p)(q)的质因子,但是(p)中有比(q)质因子大的,但它对答案并不产生贡献,我们做的是枚举删除某个质因子,然后寻求最大值(为什么要删去一个,删去多个就会使得(x)下降,导致不是最优解)

    所以解法就是 :枚举 (q)的每一个质因子,然后令(p)去除以它,直到(p)中的质因子的数要小于(q)中质因子数,然后比较出最大值来,然后就是答案;

    总复杂度 O((tsqrt{q})


    先对 (p,q) 质因数分解,设 ({a_i}) 为质数集,({b_i}) 为对应质数的次数:

    $$p=prod a_{i}^{b1_i}$$

    $$q=prod a_{i}^{b2_i}$$

    ((x|p) land (q mid {x})),则 (x) 质因数分解后有:

    $$x=prod a_{i}^{b3_i}$$

    $$p=k imes x =k imes prod a_{i}^{b3_i}(kin mathbf{N}^*)$$

    $$∃a_j|q, b3_j < b2_j$$

    第二个条件表示 (x|p),第三个条件表示存在一个整除 (q) 的质数 (a_j),它在 (x) 中的次数比在 (q) 中的次数要小,从而使 (q mid x)

    显然,最优的 (x) 一定是 (p) 抠去一些质因子 (a_j),使得该质因子在 (p) 中的次数小于 (q) 中的次数后剩下的值。

    显然抠去的质因子最多有一个。

    所以可以枚举 (q) 的所有质因子并进行计算。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #define int long long
    #define INF (1e13 + 7)
    #define MANX MAXN
    #define MAXN 2000000
    
    using namespace std;
    
    inline int read()
    {
    	int x = 0, f = 1; char c = getchar();
    	while (c > '9' || c < '0') {if (c == '-') f = -1; c = getchar();}
    	while (c >= '0' && c <= '9') {x = x * 10 + (c ^ 48); c = getchar();}
    	return f * x;
    }
    
    int a[MAXN], b[MAXN], numa, numb;
    
    signed main()
    {
    	int t = read();
    
    	while (t--)
    	{
    		int p = read(), q = read();
    		
    		if (q > p || p % q != 0) {cout << p; puts(""); continue;}//---
    		
    		int x = p, y = q, ans = 1;//---
    		
    		for (int i = 2; i <= sqrt(y); i++)
    		{
    			if (y % i == 0)
    			{
    				numa = 0, numb = 0;
    				while (x % i == 0) x /= i, numa++;
    				while (y % i == 0) y /= i, numb++;
    				int num = numa - numb + 1, k = p;//p的质数的数量减去q质数的数量 
    				for (int j = num; j; j--) k /= i;
    				ans = max(ans, k);
    			}
    		}
    		
    		if (y != 1)
    		{
    			numa = 0, numb = 0;
    			while (x % y == 0) x /= y, numa++;
    			numb++;
    			int num = numa - numb + 1, k = p;
    			for (int i = num; i; i--) k /= y;
    			ans = max(ans, k);
    		}
    
    		cout << ans;
    		puts("");
    	}
    	return 0;
    }
    

    (T4), (萃香摘西瓜)

    题目描述

    萃香所处的环境被简化为一个长为h,宽为w的网格平面。X坐标范围为[1,w],y坐标范围为[1,h]。

    她初始(第1个时刻)站在坐标为sx,sy的方格。

    西瓜可能在任意一个方格出现,在每个时间单位,它们可能向任何一个方向移动,也可能静止不动。西瓜的位置和移动的轨迹是已知的。西瓜的总数为n个,但只有m个西瓜可以被萃###香抱走,因为其他都太大了,可能会砸伤她。

    整个过程会持续T个时刻。萃香希望可以抱走全部的m个西瓜,并且在任何时候避免与任何一个过大的西瓜处在同一位置。抱走的方式为在某个时刻,与该西瓜处于同一位置。另外,###由于萃香不愿耗费过多体力到处乱跑,她每个时刻可以选择静止不动,也可以选择移动到相邻的四个格子之一,只要不越出环境边界。如果选择移动到相邻格子,则算作移动了一次。###(第1个时刻萃香刚站定,无法移动)

    在每个时刻,如果萃香选择移动,可以认为萃香与西瓜同时从原来的位置移到了新的位置,没有先后顺序。

    萃香想要知道,不被任何一个大西瓜砸中,并得到所有的m个小西瓜的情况下,最少需要移动多少次。

    输入格式

    第一行五个整数h,w,T,sx,sy,含义见题目描述。

    第二行两个整数n,m,含义见题目描述。

    接下来n段数据,每一段描述了一个西瓜的出现位置,时间,移动方式,是否可以被抱走等内容,具体如下:

    首先一行,两个整数t1,t2,表示西瓜在t1时刻出现, t2时刻消失。若t2=T+1,表示西瓜在最后一个时刻也不消失。保证西瓜至少存在一个时刻。

    接下来一行一个整数a,只能为0或1,0表示这个西瓜需要避开,1表示这个西瓜需要抱走。数据保证需要抱走的西瓜恰好有m个。

    接下来t2-t1行,每一行两个整数x,y,顺序描述了从t1时刻到t2-1时刻,该西瓜的坐标。西瓜的移动不一定是连续的,并且是一瞬间完成的,所以无需考虑萃香是否站在了移动路径###上。

    输出格式

    如果萃香在整个T时刻内无法避免被大西瓜砸中或者无法收集到所有m个小西瓜,输出-1,否则输出一个整数,表示萃香需要移动的最少次数。

    输入输出样例

    输入

    5 5 10 3 3

    1 1

    1 11

    1

    3 4

    5 2

    3 5

    1 1

    5 4

    3 4

    2 1

    1 1

    1 1

    5 5

    输出

    1

    说明/提示

    样例说明:第2~4个时刻萃香站着不动,在第6个时刻,西瓜出现在萃香旁边,萃香移动到(3,4)位置即可抱走这个西瓜。

    数据范围和提示:

    子任务可能出现两种特殊性质A和B

    A: 所有西瓜t1=1,t2=T+1

    所有西瓜全程都静止在原地,不会发生移动。

    B:m=0

    共有10个子任务。

    对于子任务1,具有特殊性质A和B

    对于子任务2~3,仅具有特殊性质A

    对于子任务4~5,仅具有特殊性质B

    对于子任务6~10,不具有任何一个特殊性质。

    对于全部子任务

    1<=所有横坐标范围<=w

    1<=所有纵坐标范围<=h

    1<=h,w<=5

    1<=T<=100

    1<=t1<=T

    2<=t2<=T+1

    t1<t2

    1<=n<=20

    0<=m<=10

    m<=n

    一个位置不会同时出现两个或以上西瓜。

    考试的时候我想到了状态压缩(DP),然后我觉得,西瓜的状态我就多设一维来表吧,好理解,还容易推状态转移方程(然而,我并没有推出来,只好打了个暴力,骗了点分)

    首先说一下为什么不能多设一维表示状态,

    按学长的话,就是多设一维的后对答案没有贡献,只是判断了下一个点是能够走罢了

    解题思路:

    我们对西瓜进行状态压缩,然后我们设一个all将m转化成状态压缩,然后我们在读入的时候,进行一下预处理,预处理的就是类似于画一个地图 (s),然后(s_{t,x,y})就表示在t时刻,坐标为((x,y))的西瓜的存在状态;

    同时我们设一个 (f_{time,x,y,sum})表示t时刻,到坐标((x,y))取得sum个西瓜的最小的步数

    同时我们所求的为最短路径,那么我们也就可以直接将(f)预处理为最大值,既能跑最短路还能判断一下是否能得到 (m)个西瓜,自然要是(ans==inf) 那就代表走不了,(既包含不能得到(m)个西瓜,也包含无路可走的情况(一样,无路可走也就没办法获得(m)个西瓜了))

    转移时枚举每个时刻每个位置,从能到达该位置的上个时刻的位置 (x′,y′)

    转移过来,还需要枚举上个位置的小西瓜状态;

    所以状态转移方程就出来了:

    (f_{t,x,y,huge s|s_{t,x,y}}=min{f_{t-1,x',y',huge s}+1});

    代码:

    #include <algorithm>
    #include <cctype>
    #include <cstdio>
    #include <cstring>
    #define LL long long
    const int maxn = 1024 + 1;
    const int inf = 0x3f3f3f3f;
    const int dx[5] = {0, 0, 0, 1, -1};
    const int dy[5] = {0, 1, -1, 0, 0};
    int h, w, t, sx, sy;
    int n, m, all, t1, t2;
    int f[101][10][10][maxn];
    int sum, s[101][10][10];
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){ if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    void swapmin(int &a, int b) 
    {
      if (b < a) a= b;
    }
    void prepare() 
    {
      h = read(), w = read(), t = read();
      sx = read(), sy = read();
      n = read(), m = read();
      for (int i = 1; i <= n; ++ i) 
      {
        t1 = read(), t2 = read();
        int type = read();
        if (type) sum ++;
        for (int j = t1; j < t2; ++ j) 
    	{
          int x = read(), y = read();
          if(type)
          {
          	s[j][x][y]=(1<<(sum-1));
    	  }
    	  else 
    	  {
    	  	s[j][x][y]=-1;
    	  }
        }
      }
    }
    int main() 
    {
      prepare();
      if (s[1][sx][sy] == -1) 
      {
        printf("-1");
        return 0;
      }
      
      all = (1 << m) - 1;
      memset(f, 0x3f, sizeof (f));
      f[1][sx][sy][s[1][sx][sy]] = 0;
      for (int i = 2; i <= t; ++ i) 
      {
        for (int x = 1; x <= w; ++ x) 
    	{
          for (int y = 1; y <= h; ++ y) 
    	  {
            if (s[i][x][y] == -1) continue ;
            for (int j = 0; j <= 4; ++ j) 
    		{
              int fx = x + dx[j], fy = y + dy[j];
              if (fx < 1 || fx > w || fy < 1 || fy > h) continue ;
              if (s[i - 1][fx][fy] == -1) continue ;
              for (int k = 0; k <= all; ++ k) 
    		{
    		swapmin(f[i][x][y][k | s[i][x][y]],f[i - 1][fx][fy][k]+(j>0));
    		//j是否大于0表示为是否动了	
                    }
            }
          }
        }
      }
      
      int ans = f[0][0][0][0];
      for (int x = 1; x <= w; ++ x) 
      {
        for (int y = 1; y <= h; ++ y) 
    	{
          swapmin(ans, f[t][x][y][all]);
        }
      }
      printf("%d
    ", ans < inf ? ans : -1);
      return 0;
    }
    
  • 相关阅读:
    centos7安装YouCompleteMe,vim打造成C++的IDE
    java循环定时器@Scheduled的使用
    js使用“toFixed( )”保留小数点后两位
    linux小本
    解决Maven资源过滤问题
    在Maven普通项目上添加Web app的支持
    项目中添加lib依赖
    回顾Servlet
    Tomcat 中文乱码
    Initialization failed for 'https://start.spring.io' Please check URL
  • 原文地址:https://www.cnblogs.com/Zmonarch/p/13925626.html
Copyright © 2011-2022 走看看