• 膜你赛2021.10.19



    T1

    Desciption

    亮亮梦到自己来到了魔法城堡, 但一扇巨大的石门阻拦了他通向城堡内的路。正当他沮丧之际,突然发现门上有一处机关,机关上有一张很长的纸条。亮亮拿起纸条的一端,只见上面写着打开机关的方法: “打开机关需要念动符咒,咒语是一串长为 L 的由 (0)(1) 组成的字符串。在这张长纸条上列了 (n) 个长为 (L) 的字符串,正确的咒语即是在纷繁的 (2^L) 种字符串中,与这些纸条上的字符串相异度之和最小,并且在满足这一条件下,(0) 的个数最多的字符串。两个字符串的相异度定义为对应位置不相等的字符对的个数。如‘(011)’和‘(001)’的
    相异度为 (1),因为它们有且只有第二个位置上的字符不相等。 ”亮亮拉起纸条,只觉得纸条似乎永远也拉不完。这上面有着数以万计的字符串,而每一个字符串的长度也或百或千,以人力看来是无法得到正确的咒语。你能帮帮他,让他得以进入魔法城堡,一窥其中的奥秘吗?

    Solution

    题目比较简单,直接贪心就好了。对于同一位置,如果当前位置1的个数多的话,就填1,否则就填0。

    Code

    /*
    * @Author: smyslenny
    * @Date:    2021.10.
    * @Title:
    * @Main idea:
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    #include <map>
    
    #define ll long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI
    "
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=1e9+7;
    const int M=1e3+5;
    int len,n;
    int read()
    {
        int x=0,y=1;
        char c=getchar();
        while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
        while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
        return y?x:-x;
    }
    int sum[M];
    char s[M];
    int main()
    {
    	freopen("curse.in","r",stdin);
    	freopen("curse.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",s+1);
    		len=strlen(s+1);
    		for(int j=1;j<=len;j++)
    			if(s[j]=='1') sum[j]++;
    	}
    	for(int i=1;i<=len;i++)
    	{
    		if(sum[i]>n/2) printf("1");
    		else printf("0");
    	}
    	return 0;
    }
    

    T2

    Description

    亮亮成功地念出了咒语,石门缓缓地自动移开,一道道绚丽的神光从城堡内激射而出。亮亮好奇而又兴奋地走入了城堡中,迎面有一座极长的魔法阵。
    魔法阵可以看作一条直线,它被均匀地分成了 1 000 000 000 个位置,一个位置可以看成是一个格子。有些位置上筑有法坛,一共 N 座。亮亮只有破了眼前
    的魔法阵,才能继续前进,而欲破法阵,必须毁掉所有的法坛。
    亮亮身前有两根法杖:一根颜色血红,能发红色神光,光芒可以笼罩连续 L 个位置,并摧毁这 L 个位置上所有的法坛,最多使用 R 次;另一根颜色碧绿,能发绿色神光,光芒可以笼罩连续 2L 个位置,并摧毁这 2L 个位置上所有的法
    坛,最多使用 G 次。法杖的神奇之处在于,L 的值必须由亮亮事先设定好,并且一经设定,便无
    法更改。亮亮需要在规定的次数下摧毁所有法坛,并且使得 L 最小。

    Solution

    看题目肯定知道要二分,关键是怎么去 check。

    法一

    我们发现 R,G 的范围都很大,但是考虑一下发现其实根本没有用明明考试想到了怕错了没写,后悔
    (R+Gge n) 的时候,直接输出 (1)
    然后设 (f_{i,j}) 表示第 (i) 个位置使用了 (j) 个红光,最少使用的绿光的个数。
    (f_{i,j} = min (f_{i,j},f_{l_1,j-1},f_{l_2,j}+1))
    (l_1,l_2) 就分别表示红光和绿光上一个不能笼罩的位置。

    法二

    (f_{i,j}) 表示红光使用了 (i) 次,绿光使用了 (j) 次所能到达的最远距离。

    (f_{i,j}=max(f_{i-1,j}+1,f_{i,j-1}+1))

    Code

    • 法二代码
    /*
    * @Author: smyslenny
    * @Date:    2021.10.
    * @Title:
    * @Main idea:
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    #include <map>
    
    #define ll long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI
    "
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=1e9+7;
    const int M=2e3+5;
    int n,Ans,r,g;
    int read()
    {
        int x=0,y=1;
        char c=getchar();
        while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
        while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
        return y?x:-x;
    }
    int pos[M];
    bool cmp(int a,int b)
    {
    	return a<b;
    }
    int site[M],site_2[M],f[M][M];
    bool check(int mid)
    {
    	memset(f,0,sizeof(f));
    	memset(site,0,sizeof(site));
    	memset(site_2,0,sizeof(site_2)); 
    	for(int i=1;i<=n;i++)
    		for(int j=i;j<=n;j++)
    		{
    			if(pos[j]-pos[i]+1<=mid) site[i]=j;
    			if(pos[j]-pos[i]+1<=2*mid) site_2[i]=j;
    		}
    	site[n+1]=n,site_2[n+1]=n;
    	for(int i=0;i<=r;i++)
    		for(int j=0;j<=g;j++)
    		{
    			if(i) f[i][j]=max(f[i][j],site[f[i-1][j]+1]);
    			if(j) f[i][j]=max(f[i][j],site_2[f[i][j-1]+1]);
    		}
    	return f[r][g]==n;
    }
    int main()
    {
    	freopen("light.in","r",stdin);
    	freopen("light.out","w",stdout); 
    	n=read(),r=read(),g=read();
    	for(int i=1;i<=n;i++) pos[i]=read();
    	sort(pos+1,pos+1+n,cmp);
    	if(r+g>n)
    	{
    		printf("1
    ");
    		return 0;
    	}
    	int l=0,r=pos[n];
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid))
    			r=mid-1,Ans=mid;
    		else 
    			l=mid+1;
    	}
    	printf("%d
    ",Ans);
    	return 0;
    }
    

    T3

    Description

    破了魔法阵后,亮亮进入了一座迷宫。这座迷宫叫做“梦境迷宫” ,亮亮只有走出这座迷宫,才能从睡梦中醒来。梦境迷宫可以用无向图来表示。它共有 n 个点和 m 条双向道路,每条道路都有边权,表示通过这条道路所需的时间,且每条道路可以多次经过。亮亮位于
    一号点,而出口则是 (n) 号点。原本,亮亮该找到一条最短路,快速冲出迷宫,然而,梦境迷宫的特殊之处在于,如果沿着最短路到达出口,亮亮就会永远陷入梦境。因此,亮亮必须寻找一条次短路。次短路的长度须严格大于最短路(可以有
    多条)的长度,同时又不大于所有除最短路外的道路的长度。
    你的任务,就是编写一个程序,帮助亮亮找到通向出口的次短路。

    Solution

    次短路的板子题。但是我挂了50分
    因为一个点可能更新多次,所以要选择 spfa。

    Code

    /*
    * @Author: smyslenny
    * @Date:    2021.10.
    * @Title:
    * @Main idea:
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    #include <map>
    
    #define ll long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI
    "
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=1e9+7;
    const int M=1e5+5;
    int n,m;
    int read()
    {
        int x=0,y=1;
        char c=getchar();
        while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
        while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
        return y?x:-x;
    }
    struct ed{
    	int u,v,w,net;
    }edge[M<<1];
    int head[M],num;
    void addedge(int u,int v,int w)
    {
    	edge[++num].u=u;
    	edge[num].v=v;
    	edge[num].w=w;
    	edge[num].net=head[u];
    	head[u]=num;
    }
    queue<int> q;
    int dis[M],S_dis[M],vis[M]; 
    void spfa(int s)
    {
    	memset(dis,INF,sizeof(dis));
    	memset(S_dis,INF,sizeof(S_dis));
    	dis[s]=0;
    	q.push(s);
    	vis[s]=1;
    	while(!q.empty())
    	{
    		int u=q.front();
    		q.pop();
    		vis[u]=0;
    //		if(u==n) continue;
    		for(int i=head[u];i;i=edge[i].net)
    		{
    			int v=edge[i].v;
    			if(dis[v]>dis[u]+edge[i].w)
    			{
    				dis[v]=dis[u]+edge[i].w;
    				if(!vis[v])
    				{
    //					vis[v]=1;
    					q.push(v);
    				}
    			}
    			else if(dis[v]==dis[u]+edge[i].w) 
    			{
    				if(S_dis[v]>S_dis[u]+edge[i].w)
    				{
    					S_dis[v]=S_dis[u]+edge[i].w;
    					if(!vis[v])
    					{
    //						vis[v]=1;
    						q.push(v);
    					}
    				}
    			}
    			else
    				if(S_dis[v]>dis[u]+edge[i].w)
    				{
    					S_dis[v]=dis[u]+edge[i].w;
    					if(!vis[v])
    					{
    //						vis[v]=1;
    						q.push(v);
    					}
    				}
    		}
    	}
    }
    int main()
    {
    	freopen("maze.in","r",stdin);
    	freopen("maze.out","w",stdout); 
    	n=read(),m=read();
    	for(int i=1,u,v,w;i<=m;i++)
    	{
    		u=read(),v=read(),w=read();
    		addedge(u,v,w);
    		addedge(v,u,w);
    	}
    	spfa(1);
    	printf("%d
    ",S_dis[n]);
    	return 0;
    }
    /*
    6 7
    1 2 8
    2 3 6
    3 6 5
    1 4 2
    4 6 11
    1 5 9
    5 6 1
    5 7
    1 2 1
    2 3 1
    3 4 1
    4 5 1
    2 4 4
    3 5 2
    1 5 6
    */
    
    本欲起身离红尘,奈何影子落人间。
  • 相关阅读:
    兼容ie6浏览器窗口四角固定背景代码
    实用的js判断浏览器类型及版本
    测试
    C#动态获取鼠标位置的颜色
    对指定的网页进行截图
    C#中使用 SendMessage 向非顶端窗体发送组合键
    ProtelDXP练习作品51单片机最小系统
    对非顶端窗口截图
    C#直接操作并口
    单片机实现的数字钟
  • 原文地址:https://www.cnblogs.com/jcgf/p/15427251.html
Copyright © 2020-2023  润新知