zoukankan      html  css  js  c++  java
  • CSP-J 2021 题解

    T1 分糖果

    Problem

    给出 (L,R,n),求出最大的 (x\% n (Lle xle R))

    Solution

    简单的分类讨论。

    (R-Lge n),说明模 (n) 的余数 (0sim n-1) 都是存在的, 那么答案就是 (n-1)

    (R-L<n),这种情况下又有两种情况:

    1. (lfloor frac{L}{n} floor<lfloorfrac{R}{n} floor)。说明从 (L)(R) 中经过了 (x o n-1 o 0 o y) 的情况。所以答案也是 (n-1)
    2. (lfloor frac{L}{n} floor=lfloorfrac{R}{n} floor)。此时不存在 (n-1),因此答案就是 (R\% n)

    Code

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll n,l,r,c1,c2,d1,d2;
    int main()
    {
    	freopen("candy.in","r",stdin);
    	freopen("candy.out","w",stdout);
    	scanf("%lld%lld%lld",&n,&l,&r);
    	if (r-l>=n) printf("%lld
    ",n-1);
    	else
    	{
    		c1=l/n;c2=l%n;
    		d1=r/n;d2=r%n;
    		if (c1==d1) printf("%lld
    ",d2);
    		else printf("%lld
    ",n-1);
    	} 
    	fclose(stdin);fclose(stdout);
    	return 0;
    } 
    

    T2 插入排序

    Problem

    给出一个含有 (n) 个元素的数组 (a)。有 (m) 次操作,每次可以修改某个数的值或者查询某个数的排名。

    修改操作最多 5000 次。

    Solution

    这题原本跟平衡树有点关系,但是看到限制:

    至多有 5000 次操作属于类型一。

    最多进行 5000 次修改。这意味着一次修改后求出所有元素的排名,到下次修改前的查询都是可以 (O(1)) 查询的。

    那么我们只需要 (O(n)) 修改就可以轻松通过此题。

    可以先预处理出每个数的排名,每次修改判断改后的值和改前的值的大小关系,选择向后还是向前修改。

    Code

    #include<bits/stdc++.h>
    #define N 8005
    using namespace std;
    struct node
    {
    	int id,val;
    }a[N];
    int n,q,x,y,opt,rk[N];
    bool lst;
    bool cmp(node x,node y) 
    {
    	if (x.val<y.val) return true;
    	if (x.val>y.val) return false;
    	return x.id<y.id;
    }
    int main()
    {
    	freopen("sort.in","r",stdin);
    	freopen("sort.out","w",stdout);
    	scanf("%d%d",&n,&q);
    	for (int i=1;i<=n;++i)
    		scanf("%d",&a[i].val),a[i].id=i;
    	sort(a+1,a+n+1,cmp);
    	for (int i=1;i<=n;++i)
    		rk[a[i].id]=i;
    	while (q--)
    	{
    		scanf("%d",&opt);
    		if (opt==1)
    		{
    			scanf("%d%d",&x,&y);
    			x=rk[x];
    			if (y<a[x].val)
    			{
    				a[x].val=y;
    				for (int i=x-1;i;--i)
    				{
    					if (a[i].val>a[i+1].val||(a[i].val==a[i+1].val&&a[i].id>a[i+1].id))
    					{
    						node t;
    						t=a[i];a[i]=a[i+1];a[i+1]=t;
    					}
    				}
    			}
    			else if (y>a[x].val)
    			{
    				a[x].val=y;
    				for (int i=x;i<n;++i)
    				{
    					if (a[i].val>a[i+1].val||(a[i].val==a[i+1].val&&a[i].id>a[i+1].id))
    					{
    						node t;
    						t=a[i];a[i]=a[i+1];a[i+1]=t;
    					}
    				}
    			}
    			for (int i=1;i<=n;++i)
    				rk[a[i].id]=i;
    		}
    		if (opt==2)
    		{
    			scanf("%d",&x);
    			printf("%d
    ",rk[x]);
    		}
    	}
    	fclose(stdin);fclose(stdout); 
    	return 0;
    }
    

    T3 网络连接

    Problem

    (n) 台计算机,每台要么为服务机要么为用户机。

    每台计算机有一个地址 (s),形如 (a.b.c.d:e),满足 (0le a,b,c,dle 255,0le ele 65535),且 (a,b,c,d,e) 都没有前导 0。

    对于每台服务机,若地址不合法输出 ( ext{ERR}),若地址已经出现过输出 ( ext{FAIL}),否则输出 ( ext{OK})

    对于每台客户机,若地址不合法输出 ( ext{ERR}),若地址出现过则输出对应服务机,否则输出( ext{FAIL})

    Solution

    比较明显的一个哈希。

    首先先判断地址的合法性,注意前导0,(a,b,c,d,e) 的大小范围和 (.) 以及 (:) 的个数。

    (a,b,c,d,e) 拼起来成为一个长度最大为 17 的数字,可以用 ( ext{long long}) 存储。

    判断该数字是否出现过,并根据计算机的类型输出对应的答案。

    Code

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    int n,sum,num1,num2,x,y,opt;
    ll res;
    bool bj;
    char ch,lst,llst;
    struct node
    {
    	int id;
    	ll val;
    }h[19260820];
    void charu(ll val,int id)
    {
    	ll s=val%19260817;
    	while (h[s].val)
    	{
    		if (h[s].val==s)
    		{
    			x=2;
    			return;
    		}
    		++s;
    		if (s==19260817) s=0;
    	}
    	h[s].val=s;
    	h[s].id=id;
    	x=1;
    }
    void chazhao(ll val)
    {
    	ll s=val%19260817;
    	while (h[s].val)
    	{
    		if (h[s].val==s)
    		{
    			y=h[s].id;
    			x=1;
    			return;
    		}
    	}
    	x=2;
    }
    int main()
    {
    	freopen("network.in","r",stdin);
    	freopen("network.out","w",stdout);
    	scanf("%d",&n);
    	ch=getchar();
    	for (int i=1;i<=n;++i)
    	{
    		while (ch!='S'&&ch!='C') ch=getchar();
    		if (ch=='S') opt=1;
    		else opt=2;
    		while ((ch<'0'||ch>'9')&&ch!='.'&&ch!=':') ch=getchar();
    		bj=true;num1=num2=0;sum=0;res=0;
    		lst=' ';llst=' ';
    		while ((ch>='0'&&ch<='9')||ch=='.'||ch==':')
    		{
    			if (ch>='0'&&ch<='9'&&lst=='0'&&(llst=='.'||llst==':'||llst==' ')) bj=false;
    			if ((ch=='.'||ch==':'||ch==' ')&&(lst=='.'||lst==':'||lst==' ')) bj=false;
    			if (ch>='0'&&ch<='9') 
    			{
    				if (sum<=65535) sum=sum*10+(ch-'0'),res=res*10+(ch-'0');
    			}
    			else
    			{
    				if (sum>255) bj=false;
    				sum=0;
    				if (ch=='.') ++num1;
    				if (ch==':') 
    				{
    					++num2;
    					if (num1!=3) bj=false;
    				}
    			}
    			llst=lst;lst=ch;
    			ch=getchar();
    		}
    		if (sum>65535||!bj||num1!=3||num2!=1||lst==':') printf("ERR
    ");
    		else
    		{
    			x=y=0;
    			if (opt==1)
    			{
    				charu(res,i);
    				if (x==1) printf("OK
    ");
    				else printf("FAIL
    ");
    			}
    			else
    			{
    				chazhao(res);
    				if (x==1) printf("%d
    ",y);
    				else printf("FAIL
    ");
    			}
    		}
    	}
    	fclose(stdin);fclose(stdout);
    	return 0;
    }
    

    T4 小熊的果篮

    Problem

    给出一个长度为 (n) 的 01 串,每次删除连续的 1 或 0 的第一个 1/0 ,问每次删去的数字的编号。

    注意删除数字后存在原本不连续的变得连续。

    Solution

    考虑将每个块合并,例如样例 2 就可以合并成 4 3 3 2 1 1 2 4。

    把各个块存入队列中,每次取出各个块的首位,更新,合并。

    考虑时间复杂度,有一种卡到最劣的构造是 1 2 3 4…… (sqrt{n})

    易证这种情况下的时间复杂度为 (mathcal{O}(nsqrt{n}))

    Code

    #include<queue>
    #include<cstdio>
    #define N 200005
    using namespace std;
    struct node
    {
    	int st,ed,cl;
    };
    queue<node> q,qq;
    int n,num,c[N];
    bool b[N];
    int main()
    {
    	freopen("fruit.in","r",stdin);
    	freopen("fruit.out","w",stdout);
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i)
    		scanf("%d",&c[i]);
    	c[n+1]=1-c[n];
    	for (int i=2,lst=1;i<=n+1;++i)
    		if (c[i]!=c[i-1]) q.push((node){lst,i-1,c[i-1]}),lst=i;
    	num=n;
    	while (num)
    	{
    		while (!q.empty())
    		{
    			node x=q.front();
    			q.pop();
    			while (b[x.st]&&x.st<=x.ed) x.st++;
    			if (x.st>x.ed) continue;
    			printf("%d ",x.st);
    			--num;b[x.st]=true;
    			if (x.st==x.ed) continue;
    			x.st++;
    			qq.push(x);
    		}
    		printf("
    ");
    		while (!qq.empty())
    		{
    			node x=qq.front();
    			qq.pop();
    			while (!qq.empty())
    			{
    				node y=qq.front();
    				if (x.cl==y.cl) 
    				{
    					x.ed=y.ed;
    					qq.pop();
    				}
    				else break;
    			}
    			q.push(x);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    入浅出MySQL 8.0 lock_sys锁相关优化 原创 腾讯数据库技术 腾讯数据库技术 2021-03-08
    以模型为中心,携程契约系统的演进
    bs
    外观模式
    设计接口时严格区分map、list,方便前端使用。
    t
    The HyperText Transfer Protocol (HTTP) 504
    入理解 epoll 原创 冯志明 Qunar技术沙龙 2021-03-10
    一次XSS和CSRF的组合拳进攻 (CSRF+JSON)
    当程序员具备了抽象思维 从码农到工匠 阿里巴巴中间件 2021-03-09
  • 原文地址:https://www.cnblogs.com/Livingston/p/15514955.html
Copyright © 2011-2022 走看看