zoukankan      html  css  js  c++  java
  • 10-17模拟赛记

    10-17模拟赛

    伪AK。

    T3一眼原题太激动把数组开小。

    290分,也不错。。。

    1.矩形计数

    (rect.cpp/c/pas)
    【问题描述】
    给出圆周上的 N 个点,请你计算出以这些点中的任意四个为四个角,能构成多少个矩
    形。
    点的坐标是这样描述的,给定一个数组 v[1..N],假设圆心为(0,0),圆的周长 C=∑
    v[1..N] ,第一个点坐标为(0,C/(2π))。从第一个点开始,顺时针沿圆周走 v1 个单位长度,
    此时坐标为第二个点的坐标,再走 v2 个单位长度,此时为第三个点的坐标,当走完 v1,v2..vi
    个距离后,为第 i+1 个点的坐标(全过程都是沿圆周顺时针)。特别的,走完 v1,v2..vn 个
    距离后,就会回到第一个点。
    【输入】
    输入文件名为 rect.in。
    输入共 N+1 行。
    第一行为正整数 N。
    接下来 N 行每行一个正整数。其中第 i+1 行表示的是 v[i]。
    【输出】
    输出文件名为 rect.out。
    输出共 1 行,一个整数,表示能构成的矩形的个数。

    想一下圆的性质,直径所对的圆周角是90度。

    又因为我们找的是矩形,所以矩形的对角线都是直径。

    所以统计直径数目,然后可以直接组合数求,但是数据范围下,我用了稳妥的枚举求。

    code:

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    const int wx=397;
    
    inline int read(){
    	int sum=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    	return sum*f;
    }
    
    int sum[wx],pos[wx],t[wx],flag[wx][wx],dis[wx][wx];
    int n,ans,len;
    
    int main(){
    	freopen("rect.in","r",stdin);
    	freopen("rect.out","w",stdout);
    	
    	n=read();
    	for(int i=1;i<=n;i++)pos[i]=read(),len+=pos[i];
    	for(int i=2;i<=n;i++){
    		sum[i]=sum[i-1]+pos[i-1];
    	}
    	if(len&1){printf("0
    ");return 0;}
    	len=len/2;
    	for(int i=1;i<=n;i++){
    		for(int j=i+1;j<=n;j++){
    			int tmp=sum[j]-sum[i];
    			dis[i][j]=dis[j][i]=tmp;
    			if(tmp==len){
    				t[i]=j; t[j]=i; 
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=i+1;j<=n;j++){
    			if(t[i]&&t[j]&&!flag[i][j]&&!flag[j][i]&&!flag[t[i]][t[j]]&&!flag[t[j]][t[i]]&&dis[i][j]==dis[t[i]][t[j]]&&t[i]!=j&&t[j]!=i){
    				ans++;
    				flag[i][j]=flag[j][i]=flag[t[i]][t[j]]=flag[t[j]][t[i]]=1;
    			}
    		}
    	}
    	printf("%d
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    2.祖先

    (ancestor.cpp/c/pas)
    【问题描述】
    任何一种生物的 DNA 都可以表示为一个由小写英文字母组成的非空字符串。科学家发
    现,所有的生物都有可能发生变异。所谓变异,就是子代的 DNA 串与父代的 DNA 串有差
    异。每次变异,DNA 串中恰好有一个字符会变成两个任意的字符。一共有 n 种可能的变异。
    变异 ai->bici 表示字符 ai 有可能变异为两个字符 bici。详细来说,就是删掉一个字符 ai,之
    后在原来 ai 的位置处,插入 bi,ci 两个字符(注意字符 bi 必须在 ci 的前面)。每种变异都
    有可能发生任意多次。可以发现,每变异一次,DNA 串的长度会加 1。
    如果有一种生物 a,他的 DNA 串是 s1,另外存在一种生物 b,他的 DNA 串是 s2。如
    果 s2 可以通过若干次变异变为 s1,那么生物 b 就被叫做生物 a 的祖先。
    现在,给定一种生物,他的 DNA 串是 s。请找出他的一个祖先,且这个祖先的 DNA 串
    尽量短。
    【输入】
    输入文件 ancestor.in,共 n+2 行。
    第一行包含一个非空字符串 s。
    第二行含有一个整数 n,表示所有可能的变异。
    接下来 n 行,每行描述一种可能的变异,按照 ai->bici 的格式。
    s,ai,bi,ci 仅包含小写英文字母。
    请注意:一种变异可能出现多次。
    【输出】
    输出文件名为 ancestor.out。
    输出只有一行,一个整数,表示祖先 DNA 串的最短长度。

    一眼DP,不过直接暴力DP的话转移很麻烦。

    取巧做一下预处理就好了。

    毕竟数据范围小随便乱搞。

    code:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int wx=77;
    
    inline int read(){
    	int sum=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    
    char c[wx],tmp[wx];
    int f[wx][wx],flag1[wx],flag2[wx],flag3[wx];
    bool ok[wx][wx][wx];
    int n;
    int a[wx];
    
    int main(){
    	freopen("ancestor.in","r",stdin);
    	freopen("ancestor.out","w",stdout);
    	
    	scanf("%s",c+1);
    	n=read();
    	for(int i=1;i<=n;i++){
    		scanf("%s",tmp+1);
    		flag1[i]=tmp[1]-'a'+1;
    		flag2[i]=tmp[4]-'a'+1;
    		flag3[i]=tmp[5]-'a'+1;
    	}
    	int len=strlen(c+1);
    	for(int i=1;i<=len;i++)ok[i][i][c[i]-'a'+1]=1;
    	for(int l=1;l<=len;l++){
    		for(int i=1;i<=len-l+1;i++){
    			int j=i+l-1;
    			for(int k=i+1;k<=j;k++){
    				for(int zmj=1;zmj<=n;zmj++){
    					if(ok[i][k-1][flag2[zmj]]&&ok[k][j][flag3[zmj]])ok[i][j][flag1[zmj]]=1;
    				}
    			}
    		}
    	}
    	for(int l=1;l<=len;l++){
    		for(int i=1;i<=len-l+1;i++){
    			int j=i+l-1;
    			for(int k=1;k<=26;k++){
    				if(ok[i][j][k])f[i][j]=1;
    			}
    			if(f[i][j]==0){
    				f[i][j]=0x3f3f3f3f;
    				for(int k=i+1;k<=j;k++){
    					f[i][j]=min(f[i][j],f[i][k-1]+f[k][j]);
    				}
    			}
    		}
    	}
    	printf("%d
    ",f[1][len]);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    3.Formula 1

    (f1.cpp/c/pas)
    【问题描述】
    F1,中文全称为一级方程式锦标赛,是最高级的方程式赛车比赛,现在你作为一名选
    手参加了一场 F1 的比赛,比较特殊地,本次比赛是在一个 N 个点 M 条边的无向图上举行
    的。
    起点是 S,终点是 T,每条边长度为 1 公里,赛车每行驶 1 公里耗油 1 个单位,途中共
    有 k 个加油站,每经过加油站时,可以把油加满,但你的赛车设计顾问告诉你,油箱容量越
    大,赛车跑的就越慢。为了追求最快的速度,在能顺利到达终点,不会中途没油的前提下,
    你希望最小化油箱的容量(注意,虽然油箱变小可能导致路径变长,但我们只关心最小化的
    油箱)。
    【输入】
    输入文件 f1.in。
    第一行一个正整数 T 表示测试数据组数,每组数据格式如下:
    第一行三个整数,N,M,K,表示无向图的点数,边数,加油站数。
    第二行 K 个正整数 i1,i2..ik 表示这些点上有加油站(可能重复,保证至少一个加油站在
    S 点)。
    接下来 M 行,每行两个正整数 Bi,Ei 表示有一条连接(Bi,Ei)的双向边(可能有重边和自
    环)。
    最后一行两个正整数 S,T 表示起点、终点。
    【输出】
    输出文件名为 f1.out。
    对于每组数据,如果没法到达终点,输出-1,否则输出最小化的油箱容量

    这道题机房其他人都是写的二分,两个大佬切掉了,可是我数组开小了只得90。。。

    简直是bzoj4242原题,甚至更加简单。

    小岛原理建边真的骚啊。

    代码不放了,跟水壶几乎一样。

  • 相关阅读:
    Codeforces Global Round 11 E Xum
    【NFLSPC #2】Polynomial
    【SHOI2015】脑洞治疗仪 题解 (线段树)
    CDQ分治与整体二分 学习笔记
    二维树状数组 学习笔记
    博弈论 学习笔记
    【JSOI2007】文本生成器 题解(AC自动机+动态规划)
    【NOI2018】归程 题解(kruskal重构树+最短路)
    【NOI2017】游戏 题解(2-SAT+缩点)
    【BZOJ4398】福慧双修 题解(建图优化)
  • 原文地址:https://www.cnblogs.com/wangxiaodai/p/9805326.html
Copyright © 2011-2022 走看看