zoukankan      html  css  js  c++  java
  • NOIP 模拟题


    数据可私信我.

    T1 : grid

    题目:在一个(n*n)的方格中,你只能斜着走。为了让问题更简单,你还有一次上下左右走的机。给你一个起点,和终点,询问从起点到终点的最短路.
    输入样例
    8 2 3 7 5
    输出样例
    5

    数据范围:
    对于 (20%) 的数据满足:(n<=10)
    对于另外 (30%) 的数据满足:(n<=1000)
    对于 (100%)的数据满足:(n<=1e18,s1,t1,s2,t2<=n)
    期望:100
    实际得分:100
    解:
    还是比较不错的画图题.
    大概就是先斜着走满max(abs(s1 - s2),abs(t1 - t2))
    因为斜着是h ++,l ++么(不管坐标,只管相对位置的话)
    所以剩下的分两种情况:
    1.偶数
    直接斜着来回条就好了
    2.奇数
    先直接偶数跳,然后动用上下左右走的机会.
    CODE

    #include <iostream>
    #include <cstdio>
    #define ll long long
    
    ll max(ll a,ll b) {
    	return a > b ? a : b ;
    }
    
    ll abs(ll a) {
    	return a > 0 ? a : -a;
    }
    
    int main() {
    	freopen("grid.in","r",stdin);
    	freopen("grid.out","w",stdout);
    	ll n,s1,s2,t1,t2,ans;
    	std::cin >> n >> s1 >> t1 >> s2 >> t2;
    	ans = max(abs(s1 - s2),abs(t1 - t2));
    	std::cout << ans;
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    T2 : ling

    期望:100
    实际得分:100
    【题目描述】
    作为一场 NOIP 良心模拟赛,需要一道小清新字符串题。
    xxx 最近在研究语言学(glossology)。他对正在研究的语言有一个疑问。在这门语言中,所有
    单词是按照同一方式生成的:首先确定一个基本串(base)(长度至少为 3) ,然后在基本串后加任
    意多个(可以不加)长度为 2 或 3 的后缀串(suffix),得到单词s。要求相邻后缀串不能相同。
    现在他有一些单词 s, 他想知道, 在基本串任意的情况下, 可能参与构成 s 的后缀串有哪些。
    特别的, 对于有些单词, 其相邻后缀串可以相同, 他会用 type 标注 (对于 T 组数据都有效) 。
    若 type = 0,则相邻后缀串不能相同;否则相邻后缀串可以相同(type 可以是除 0 外的任
    何 int 内的整数) 。
    【输入格式】
    第一行两个整数 T,type,表示数据组数和后缀串是否有限制(见题目描述) 。
    接下来 T 行,每行一个字符串,表示要求的单词 s。
    【输出格式】
    对于每组数据:
    第一行输出k,表示可能构成 s 的后缀串个数。
    接下来 k 行,每行输出一个字符串 suf i ,表示一个可能的后缀串。
    所有后缀串按字典序从小到大输出。
    【样例 1 输入】
    2 0
    abc
    acacaca
    【样例 1 输出】
    0
    2
    aca
    ca
    【样例 1 解释】
    对于第一个 s,要求基本串长度至少为 3,所以不存在合法后缀串。
    对于第二个 s,有两种情况:acac 做基本串时,合法后缀串有 aca;acaca 做基本串时,合
    法后缀串有 ca。即:acacaca 与 acacaca。
    【样例 2 输入】
    1 0
    abcabcabab
    【样例 2 输出】
    5
    ab
    bab
    bca
    ca
    cab
    【样例 2 解释】
    合法的划分为:abcabcabab、abcabcabab、abcabcabab。 (红色为基本串,蓝色、紫色为
    后缀串)
    【样例 3 输入】
    1 1
    abcabcabab
    【样例 3 输出】
    7
    ab
    abc
    bab
    bc
    bca
    ca
    cab

    数据范围:
    对于所有的的测试数据满足 (T <= 10,sum |s|<=5e4)
    题解:
    考虑DP
    f[i][0/1]表示以i为起点的2个字串和三个字串是否可行
    状态方程就是:
    在满足前后两个字串相等的条件下$$f [i][1] = f[i + 3][0] | f[i + 3][1]$$
    在满足前后两个字串相等的条件下$$f[i][0] = f[i + 2][0] | f[i + 2][1]$$
    时间复杂度:(O(n))
    按字典序的时候比较神奇.因为全是小写字母,可以用(ok1[28][28],ok2[28][28][28])来确定这个字符的出现及输出.
    我的方法就是map判断是否可行和string + sort.
    非常麻烦
    My_CODE

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <queue>
    #include <cstdio>
    #include <map>
    const int maxN = 5e4 + 7;
    using namespace std;
    
    bool f[maxN][2];//0是后面一个和自己,1是后面两个和自己 
    string emm,s;
    
    //DP 
    
    string ans[maxN];
    int num;
    map <string,int> m;
    //去重 
    
    void init() {
    	emm.clear();
    	s.clear();
    	num = 0;
    	m.clear();
    	memset(f,0,sizeof(f));
    }
    
    void work1() {
    	cin >> emm;
    	int len = emm.length();
    	s = emm;
    	if(len <= 4) {
    		puts("0");
    		return;
    	}
    	if(len == 5) {
    		puts("1");
    		cout << s[len - 2] << s[len - 1]  << '
    ';
    		return ;
    	}
    	f[len - 1][0] = true;
    	f[len - 2][1] = true;
    	for(int i = len - 3;i > 3;-- i) {
    		f[i][0] = f[i + 2][1] | f[i + 2][0];
    		f[i][1] = f[i + 3][0] | f[i + 3][1];
    	}
    	for(int i = 1;i <= len;++ i) {
    		if(f[i][0]) {
    			string tmp;
    			for(int j = 0;j <= 1;++ j) {
    				tmp += s[i + j - 1];
    			}
    			if(!m[tmp]) {
    				ans[++ num] = tmp;
    				m[tmp] = 1;
    			}
    		}
    		if(f[i][1]) {
    			string tmp;
    			for(int j = 0;j <= 2;++ j) {
    				tmp += s[i + j - 1];
    			}
    			if(!m[tmp]) {
    				ans[++ num] = tmp;
    				m[tmp] = 1;
    			}
    		}
    	}
    	printf("%d
    ",num);
    	sort(ans + 1,ans + num + 1);
    	for(int i = 1;i <= num;++ i) {
    		cout << ans[i];
    		puts("");
    	}
    	return;
    }
    
    void work() {
    	cin >> emm;
    	int len = emm.length();
    	s = emm;
    	if(len <= 4) {
    		puts("0");
    		return;
    	}
    	if(len == 5) {
    		puts("1");
    		cout << s[len - 2] << s[len - 1]  << '
    ';
    		return ;
    	}
    	f[len - 1][0] = true;
    	f[len - 2][1] = true;
    	for(int i = len - 3;i > 3;-- i) {
    		bool flag1 = false,flag2 = false;
    		for(int j = 0;j <= 2;++ j) if(s[i + j - 1] != s[i + 3 + j - 1]) flag1 = true;
    		f[i][0] = f[i + 2][1];
    		f[i][1] = f[i + 3][0];
    		if(flag1) f[i][1] = f[i][1] | f[i + 3][1];
    		for(int j = 0;j <= 1;++ j) if(s[i + j - 1] != s[i + 2 + j - 1]) flag2 = true;
    		if(flag2) f[i][0] = f[i][0] | f[i + 2][0];
    	}
    	for(int i = 1;i <= len;++ i) {
    		if(f[i][0]) {
    			string tmp;
    			for(int j = 0;j <= 1;++ j) {
    				tmp += s[i + j - 1];
    			}
    			if(!m[tmp]) {
    				ans[++ num] = tmp;
    				m[tmp] = 1;
    			}
    		}
    		if(f[i][1]) {
    			string tmp;
    			for(int j = 0;j <= 2;++ j) {
    				tmp += s[i + j - 1];
    			}
    			if(!m[tmp]) {
    				ans[++ num] = tmp;
    				m[tmp] = 1;
    			}
    		}
    	}
    	printf("%d
    ",num);
    	sort(ans + 1,ans + num + 1);
    	for(int i = 1;i <= num;++ i) {
    		cout << ans[i];
    		puts("");
    	}
    	return;
    }
    
    int main() {
    	freopen("ling.in","r",stdin);
    	freopen("ling.out","w",stdout);
    	int T,type;
    	scanf("%d%d",&T,&type);
    	if(!type) {
    		while(T --) {
    			init();
    			work();	
    		}	
    	}
    	else {
    		while(T --) {
    			init();
    			work1();
    		}
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    STD_CODE

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define pc putchar
    const int N=50005;
    
    bool f[N][2]/*0:2 1:3*/,ok2[28][28],ok3[28][28][28];
    char s[N];
    
    void Work(const int type)
    {
    	memset(f,0,sizeof f);
    	memset(ok2,0,sizeof ok2), memset(ok3,0,sizeof ok3);
    
    	scanf("%s",s+1);
    	int n=strlen(s+1);
    	std::reverse(s+1,s+1+n);
    
    	int tot=0; n-=3;
    	if(n>=2) f[2][0]=1, ++tot, ok2[s[2]-'a'][s[1]-'a']=1;
    	if(n>=3) f[3][1]=1, ++tot, ok3[s[3]-'a'][s[2]-'a'][s[1]-'a']=1;
    
    	for(int i=4; i<=n; ++i)
    	{
    		int a=s[i]-'a', b=s[i-1]-'a', c=s[i-2]-'a';
    		if(f[i-2][1]||(f[i-2][0]&&(type||s[i]!=s[i-2]||s[i-1]!=s[i-3])))
    		{
    			f[i][0]=1;
    			if(!ok2[a][b]) ++tot, ok2[a][b]=1;
    		}
    		if(f[i-3][0]||(f[i-3][1]&&(type||s[i]!=s[i-3]||s[i-1]!=s[i-4]||s[i-2]!=s[i-5])))//i>=6
    		{
    			f[i][1]=1;
    			if(!ok3[a][b][c]) ++tot, ok3[a][b][c]=1;
    		}
    	}
    	printf("%d
    ",tot);
    	for(int i=0; i<27&&tot; ++i)
    	{
    		for(int j=0; j<27; ++j)
    		{
    			if(ok2[i][j]) --tot,pc(i+'a'),pc(j+'a'),pc('
    ');
    			for(int k=0; k<27; ++k)
    				if(ok3[i][j][k]) --tot,pc(i+'a'),pc(j+'a'),pc(k+'a'),pc('
    ');
    		}
    	}
    }
    
    int main()
    {
    	freopen("ling.in","r",stdin);
    	freopen("ling.out","w",stdout);
    
    	int T,type;
    	for(scanf("%d%d",&T,&type); T--; Work(type));
    	return 0;
    }
    

    T3 : threebody

    某CF原题.
    CF643E.
    洛谷:题目链接
    非常好的一道题,考场中由于思维太渣,处理T2部分的时候非常麻烦.导致用时太长.没有时间思考这道题,最近在学习期望这一部分,所以打算认真的做一下.
    首先要确认这是一个期望DP.
    线性性质就不必说了.
    设f[x][i]表示以x为根,(dep[x_{son}] <= h)的概率
    那么答案就是.(sum_{h = 1}^{MAX\_H}h * (f[x][h] - f[x][h - 1]))
    考虑如何更新.
    显然,可以通过(x_{son})转移,那么子节点(v = son_x)有两种情况,一个是存在边,对(f[x][h])贡献(1/2 * f[v][h - 1])的概率,二十不存在该边,概率那么就是(1/2)
    然后就成了(f[x][h] = prod_{v = son_x}(1/2 + 1/2 * f[v][h - 1]))
    更新的时候暴力更新即可,一直往上直到根节点.除掉以前的项,乘上新的项即可.
    但是如果深度特别大怎么办,注意题目中的有精度误差,那么到了很大的数就会比(1e-6)小,这个时候精度达到了,不用继续.这里选择取(Max\_H = 60).
    CODE

    #include <iostream>
    #include <cstdio>
    const int maxN = 5e5 + 7;
    const int maxH = 60;
    
    int n,fa[maxN];
    double f[maxN][maxH];
    
    inline int read() {
    	int x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9' ) {if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
    	return x * f;
    }
    
    int main() {
    	int n = 1,T = read(),opt,x;
    	for(int i = 0;i < maxH;++ i) f[1][i] = 1;
    	while(T --) {
    		opt = read();x = read();
    		if(opt == 1) {
    			fa[++ n] = x;
    			for(int i = 0;i < maxH;++ i) 
    				f[n][i] = 1;
    			double tmp1 = f[x][0],tmp2;
    			f[x][0] *= 0.5;
    			for(int Fa = fa[x],i = 1; Fa && i < maxH; Fa = fa[x = Fa],++ i)
                {
                    tmp2 = f[Fa][i];
                    f[Fa][i] /= 0.5 + 0.5 * tmp1;
                    f[Fa][i] *= 0.5 + 0.5 * f[x][i-1];
                    tmp1 = tmp2;
            	}
    		}
    		else {
    			double ans = 0;
    			for(int i = 1;i < maxH;++ i) 
    			ans += (f[x][i] - f[x][i - 1]) * i;
    			printf("%.10lf
    ",ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    ES6小点心第二弹——底部浮现弹窗
    ES6小点心之通用弹窗
    从输入URL到页面加载的过程?如何由一道题完善自己的前端知识体系!
    【quickhybrid】如何实现一个Hybrid框架
    【开源】canvas图像裁剪、压缩、旋转
    优雅的H5下拉刷新【minirefresh】
    前端筑基篇(一)->ajax跨域原理以及解决方案
    钉钉开放与商业化团队前端大量招人
    AJAX请求真的不安全么?谈谈Web安全与AJAX的关系。
    【quickhybrid】iOS端的项目实现
  • 原文地址:https://www.cnblogs.com/tpgzy/p/9691350.html
Copyright © 2011-2022 走看看