• JZOJ 2020.08.03【NOIP提高组】模拟 &&【NOIP2015模拟11.5】


    总结

    又是一日爆炸
    (T1) 不出所料报 (0) 了?!

    题目

    (T1)

    JZOJ 4315. Prime

    暴力就好了?!
    考场根本没想暴力
    赛后发现暴力跑得贼快
    只需二分一下组数的上界
    然后 (dfs) 判断能否能成功分完组
    跑时顺便统计答案就行了

    (Code)

    #include<cstdio>
    #include<iostream>
    using namespace std;
    
    const int N = 20;
    int n , a[N] , vis[N][N] , d[N][N] , cnt , ans , Mx , bz;
    
    inline int gcd(int x , int y){return y == 0 ? x : gcd(y , x % y);}
    
    inline void dfs(int x , int mid , int Max)
    {
    	if (mid > ans || mid == ans && Max >= Mx) return;
    	if (cnt > mid) return;
    	if (x > n)
    	{
    		bz = 1;
    		if (ans > mid) ans = mid , Mx = Max;
    		else if (ans == mid && Max < Mx) Mx = Max;
    		return;
    	}
    	for(register int i = 1; i <= cnt; i++)
    	{
    		int fl = 0;	
    		for(register int j = 1; j <= d[i][0]; j++)
    		if (!vis[x][d[i][j]]) 
    		{
    			fl = 1;
    			break;
    		}
    		if (fl) continue;
    		d[i][++d[i][0]] = x;
    		dfs(x + 1 , mid , max(Max , d[i][0]));
    		--d[i][0];
    	}
    	d[++cnt][++d[cnt][0]] = x;
    	dfs(x + 1 , mid , max(Max , 1));
    	--d[cnt][0] , --cnt;
    }
    
    int main()
    {
    	freopen("prime.in" , "r" , stdin);
    	freopen("prime.out" , "w" , stdout);
    	scanf("%d" , &n);
    	for(register int i = 1; i <= n; i++) scanf("%d" , &a[i]);
    	for(register int i = 1; i <= n; i++)
    		for(register int j = 1; j <= n; j++)
    		if (i != j) vis[i][j] = gcd(a[i] , a[j]) == 1 ? 1 : 0;
    	ans = 0x3f3f3f3f , Mx = 0x3f3f3f3f;
    	int l = 1 , r = n , mid;
    	while (l <= r)
    	{
    		mid = (l + r) >> 1;
    		cnt = bz = 0;
    		dfs(1 , mid , 0);
    		if (bz) r = mid - 1;
    		else l = mid + 1;
    	}
    	printf("%d %d" , ans , Mx);
    }
    

    (T2)

    JZOJ 4316. Isfind

    一眼没看出?!序列自动机?!?
    去一边,暴力又能过?!!
    天!!!
    而我想到了非暴力的解法,幸好过了,不然亏大了
    只需记录每种字母在原串出现的先后位置
    然后匹配时二分找位置判断就行了

    (Code)

    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    const int N = 1e5 + 5;
    int n , m , a[30][N] , p[30];
    char s[N];
    
    inline int binary(int t , int x)
    {
    	int l = 0 , r = p[t] , mid , res = -1;
    	while (l <= r)
    	{
    		mid = (l + r) >> 1;
    		if (a[t][mid] >= x) res = a[t][mid] , r = mid - 1;
    		else l = mid + 1;
    	}
    	return res;
    }
    
    int main()
    {
    	freopen("isfind.in" , "r" , stdin);
    	freopen("isfind.out" , "w" , stdout);
    	scanf("%d%d%s" , &n , &m , s);
    	int len = strlen(s) , pos , pos1 , fl;
    	for(register int i = 0; i < 28; i++) p[i] = -1;
    	for(register int i = 0; i < len; i++) a[s[i] - 'a'][++p[s[i] - 'a']] = i;
    	while (m--)
    	{
    		scanf("%s" , s);
    		len = strlen(s);
    		pos = -1;
    		fl = 0;
    		for(register int i = 0; i < len; i++)
    		{
    			pos1 = binary(s[i] - 'a' , pos + 1);
    			if (pos1 == -1)
    			{
    				printf("N
    ");
    				fl = 1;
    				break;
    			}
    			else pos = pos1;
    		}
    		if (!fl) printf("Y
    ");
    	}
    }
    

    实际上,它是序列自动机的模板题
    所以上个序列自动机的代码

    (Code)

    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    const int N = 1e5 + 5 , INF = 0x3f3f3f3f;
    int n , m , nxt[N][30];
    char s[N];
    
    int main()
    {
    	freopen("isfind.in" , "r" , stdin);
    	freopen("isfind.out" , "w" , stdout);
    	scanf("%d%d%s" , &n , &m , s);
    	int len = strlen(s);
    	for(register int i = 0; i <= 26; i++) nxt[len][i] = INF;
    	for(register int i = len - 1; i >= 0; i--)
    	{
    		for(register int j = 0; j <= 26; j++) nxt[i][j] = nxt[i + 1][j];
    		nxt[i][s[i] - 'a'] = i;
    	}
    	for(; m; --m)
    	{
    		scanf("%s" , s);
    		len = strlen(s);
    		int pos = -1 , fl = 0;
    		for(register int i = 0; i < len; i++)
    		{
    			pos = nxt[pos + 1][s[i] - 'a'];
    			if (pos == INF)
    			{
    				printf("N
    ") , fl = 1;
    				break;
    			}
    		}
    		if (!fl) printf("Y
    ");
    	}
    }
    

    (T3)

    JZOJ 4317. Divide

    很显然 (a_i) 有用的部分是 (gcd(a_i,p))
    然后我们就发现 (a_i imes a_j imes a_k) 相当于 (p) 的因数相乘
    我们只要处理出 (p) 的所有因数,然后 (O(tot^3)) 枚举三个因数相乘
    用桶记下每种因数在 (a) 出现的次数
    然后分类讨论算贡献即可

    (Code)

    #include<cstdio>
    using namespace std;
    typedef long long LL;
    
    const int N = 3e4 + 5 , M = 1e6 + 5;
    LL a[N] , pr[M] , buc[M] , p , ans;
    int n , tot;
    
    inline LL gcd(LL x , LL y){return y == 0 ? x : gcd(y , x % y);}
    
    int main()
    {
    	freopen("divide.in" , "r" , stdin);
    	freopen("divide.out" , "w" , stdout);
    	scanf("%d%lld" , &n , &p);
    	for(register int i = 1; i <= n; i++)
    	{
    		scanf("%lld" , &a[i]);
    		a[i] = gcd(a[i] , p);
    		++buc[(int)a[i]];
    	}	
    	for(register int i = 1; i <= p; i++)
    	if (p % i == 0) pr[++tot] = i;
    	for(register int i = 1; i <= tot; i++)
    	for(register int j = i; j <= tot; j++)
    	for(register int k = j; k <= tot; k++)
    	if (pr[i] * pr[j] % p * pr[k] % p == 0)
    	{
    		if (i == j && i == k) ans += buc[pr[i]] * (buc[pr[i]] - 1) * (buc[pr[i]] - 2) / 6;
    		else{
    			if (i == j) ans += buc[pr[i]] * (buc[pr[j]] - 1) * buc[pr[k]] / 2;
    			else if (i == k) ans += buc[pr[i]] * (buc[pr[k]] - 1) * buc[pr[j]] / 2;
    			else if (j == k) ans += buc[pr[j]] * (buc[pr[k]] - 1) * buc[pr[i]] / 2;
    			else ans += buc[pr[i]] * buc[pr[j]] * buc[pr[k]];
    		}
    	}
    	printf("%lld" , ans);
    }
    
  • 相关阅读:
    希腊字母大全
    SQL 等值连接(内连接)、自然连接(Out join,Left join,Right join)的区别
    JDK11 JAVA11下载安装与快速配置环境变量教程
    “由爱故生忧,由爱故生怖。若离于爱者,无忧亦无怖”
    How to use special characters in XML?
    Crow’s Foot Notation
    How do I unmute my Lenovo laptop?
    Nginx学习笔记--001-Nginx快速搭建
    Nginx 相关介绍
    java使用httpclient封装post请求和get的请求
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/13426157.html
Copyright © 2020-2023  润新知