zoukankan      html  css  js  c++  java
  • Codeforces#584 A~F题解

    A Paint the Numbers

    题目

    直接循环下

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
     
    const int MAXN = 110;
    int a[MAXN],ans;
    int main()
    {
        int n,i;
    	scanf("%d",&n);
    	for(i = 1;i <= n;i++)
    		scanf("%d",&a[i]);
    	sort(a + 1,a + 1 + n);
    	for(i = 1;i <= n;i++)
    	{
    		bool able = 1;
    		for(int j = 1;j < i;j++)
    			if(a[i] % a[j] == 0)
    			{
    				able = 0;
    				break;
    			}
    		if(able) ans++;
    	}
    	printf("%d",ans);
        return 0;
    }
    

    B Koala and Lights

    题目

    题目大意

    有n盏灯((1≤n≤100)) 每盏灯有两种状态(开或关),给定每盏灯的初始状态(一个01字符串 0-关,1-开)

    接下来每盏灯对应给出它的(a)(b(1≤a,b ≤5 ))

    这些灯在(b+a*k (kin [0,+infty)))时刻会改变状态

    问 同一个时刻最多有多少灯同时亮着

    因为((1≤a,b ≤5 ))

    考虑一下这个范围 求一下lcm

    大概暴力循环到200就够了

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
     
    const int MAXN = 110;
    bool sta[MAXN];
    struct node
    {
    	int a,b;
    }w[MAXN];
    int ans;
    int main()
    {
        int j,i,n;
        scanf("%d",&n);
        for(i = 1;i <= n;i++) scanf("%1d",&sta[i]);
        for(i = 1;i <= n;i++)
        	scanf("%d%d",&w[i].a,&w[i].b);
    	for(i = 0;i <= 200;i++)
        {
        	int q = 0;
        	for(j = 1;j <= n;j++)
        	{
        		if(i >= w[j].b&&(i - w[j].b) % w[j].a == 0) sta[j] = !sta[j];
        		if(sta[j]) q++;
    		}
    		ans = max(ans,q);
    	}
    	printf("%d",ans);
        return 0;
    }
    
    

    C Paint the Digits

    题目

    比较简单

    用单调队列 处理完1的

    但此时涂1不一定有这么多,判断一下涂2的最小的

    把涂1的大于涂2的最小的数给添加到涂2里就搞定了

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
     
    const int MAXN = 2e5 + 1;
    int d[MAXN],cnt;
    struct node
    {
    	int val,loc;
    }q[MAXN];
    int main()
    {
        int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		int n,i,j;
    		scanf("%d",&n);
    		cnt = 0;
    		q[cnt].val = -1;
    		for(i = 1;i <= n;i++)
    			scanf("%1d",&d[i]);
    		for(i = 1;i <= n;i++)
    		{
    			while(q[cnt].val > d[i]) cnt--;
    			q[++cnt].val = d[i];
    			q[cnt].loc = i;
    		}
    		j = 1;
          //处理涂1的
    		int fi = 0;
    		for(i = 1;i <= n;i++)
    		{
    			if(d[i] == q[j].val&&j <= cnt) j++;
    			else {
    				fi = i;
    				break;
    			}
    		}
            //找最小(不是指大小,而是位置)的涂2的
    		if(fi)
    		{
    			while(q[cnt].val > d[fi]) cnt--;
    			j = 1;
    			bool able = 0;
    			int maxl = 0;
    			for(i = 1;i <= n;i++)
    				if(d[i] == q[j].val&&j <= cnt) j++;
    				else {
    					maxl = max(maxl,d[i]);
    					if(d[i] < maxl)
    					{
    						able = 1;
    						break;
    					}
    				}
    			if(able)
    			{
    				printf("-
    ");
    				continue;
    			}
    		}
    		j = 1;
    		for(i = 1;i <= n;i++)
    			if(d[i] == q[j].val&&j <= cnt) {printf("1");j++;}
    			else printf("2");
    		putchar('
    ');
    	}
        return 0;
    }
    

    D Cow and Snacks

    相当于是一个森林

    易得每一棵树最大解为边数(-1)

    然后再累加起来用(n)减它就是(ans)

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
     
    const int MAXN = 1e5 + 1;
    vector<int> G[MAXN];
    int ans;
    bool vis[MAXN],d[MAXN];
    inline void dfs(int x)
    {
    	ans++;//
    	vis[x] = 1;
    	int i;
    	for(i = 0;i < G[x].size();i++)
    	{
    		int v = G[x][i];
    		if(!vis[v])
    			dfs(v);
    	}
    }
    int main()
    {
    	int i,n,k;
    	scanf("%d%d",&n,&k);
    	for(i = 1;i <= k;i++)
    	{
    		int u,v;
    		scanf("%d%d",&u,&v);
    		G[u].push_back(v);
    		G[v].push_back(u);
    		d[u] = d[v] = 1;
    	}
    	for(i = 1;i <= n;i++)
    		if(!vis[i]&&d[i])
    		{
    			dfs(i);	
    			ans--;
    		}		
    	printf("%d",k - ans);
        return 0;
    }
    

    E Rotate Columns (easy version)

    这道题对我来说不是很简单

    因为这道题要用状压(DP)

    而我没学

    (color{pink}{然而学会之后还是挺简单的})

    其实就是把一维记录状态

    而这状态为(10)进制数

    把她转为二进制

    得到一个(01)字符串

    分别对应每一列的状态

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    int num[15][2010],dp[2010][4100],n;
    inline int count(int x,int s)
    {
    	int i,j,ans = 0;
    	for(i = 1;i <= n;i++)
    	{
    		int sum = 0,k = 1;
    		for(j = 1;j <= n;j++)
    		{
    			if(k & s)
    				sum += num[j][x];
    			k <<= 1;
    		}
         当前的取值
    		ans = max(ans,sum);
    		for(j = n;j >= 1;j--)
    			num[j + 1][x] = num[j][x]; 
    		num[1][x] = num[n + 1][x];
          把数字往后移一位
          
    	}
    	return ans;
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		int i,j,m;
    		scanf("%d%d",&n,&m);
    		for(i = 1;i <= n;i++)
    			for(j = 1;j <= m;j++)
    				scanf("%d",&num[i][j]); 
    		int maxl = (1 << n) - 1,k;
          到这里 应该很容易看出来了
          
          dp[i][j]表示在前i列中 选取状态为j的最优解
    		for(i = 1;i <= m;i++)
    		{
    			memset(dp[i],0,sizeof(dp[i]));
    			for(j = 0;j <= maxl;j++)
    			{
    				for(k = j;;k = (k - 1) & j)
    				{
    					dp[i][j] = max(dp[i][j],dp[i - 1][k] + count(i,j - k));
    					if(!k) break;
    				}
    			}
    		}
         	DP
    		printf("%d
    ",dp[m][maxl]);
    	}
    	return 0;
    }
    

    F Rotate Columns (hard version)

    (E)题的话这题就很好做了

    (color{pink}{大水题})

    把每列的最大值记录下 按其大小从大到小排序

    然后只算前(n)

    还有就是 把(count(i,j - k))预处理一下

    但我的代码真的很神奇

    讲道理循环到(n)就可以AC了

    我改成(n+5)才过

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    int num[15][2010],dp[2010][4100],n;
    int cnt[2010][4100];
    struct node
    {
    	int maxl,it;
    	bool operator <(const node y) const {return maxl > y.maxl;}
    }row[2010];
    inline int count(int x,int s)
    {
    	int i,j,ans = 0;
    	for(i = 1;i <= n;i++)
    	{
    		int sum = 0,k = 1;
    		for(j = 1;j <= n;j++)
    		{
    			if(k & s) sum += num[j][row[x].it];
    			k <<= 1;
    		}
    		ans = max(ans,sum);
    		for(j = n;j >= 1;j--)
    			num[j + 1][row[x].it] = num[j][row[x].it]; 
    		num[1][row[x].it] = num[n + 1][row[x].it];
    	}
    	return ans;
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		int i,j,m;
    		scanf("%d%d",&n,&m);
    		for(i = 1;i <= n;i++)
    			for(j = 1;j <= m;j++)
    			{
    				scanf("%d",&num[i][j]);
    				if(i == 1) row[j].it = j,row[j].maxl = num[i][j];
    				row[j].maxl = max(row[j].maxl,num[i][j]);
    			}
    		memset(cnt,0,sizeof(cnt));
    		sort(row + 1,row + 1 + m);
    		int maxl = (1 << n) - 1,k,ans = 0;
    		for(i = 1;i <= min(n + 5,m);i++)
    			for(j = 0;j <= maxl;j++)
    				cnt[i][j] = count(i,j);	
    		for(i = 1;i <= min(n + 5,m);i++)
    		{
    			memset(dp[i],0,sizeof(dp[i]));
    			for(j = 0;j <= maxl;j++)
    			{
    				for(k = j;;k = (k - 1) & j)
    				{
    					dp[i][j] = max(dp[i][j],dp[i - 1][k] + cnt[i][j - k]);
    					ans = max(ans,dp[i][j]);	
    					if(!k) break;
    				}
    			}
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    

    G Koala and Notebook

    这题得用拆点

    之前没学过 然后这次学会了

    所以打比赛使人进步

    拆点的思路很简单

    拆点的本质是拆边

    我们这道题 把每条边 拆成 其位数条边 每条边的权值为其对应该位的数

    
    输入
    for(i = 1;i <= m;i++)
    	{
    		int j,u,v,k = i;
    		scanf("%d%d",&u,&v);
    		edge.clear();
    		while(k) {edge.push_back(k % 10);k /= 10;}
    		int Size = edge.size(),pre = u;
    		for(j = Size - 1;j >= 0;j--)
    		{
    			int w = (j == 0? v:++cnt);
    			V[pre][edge[j]].push_back(w);
    			pre = w;
    		}
    		pre = v;
    		for(j = Size - 1;j >= 0;j--)
    		{
    			int w = (j == 0? u:++cnt);
    			V[pre][edge[j]].push_back(w);
    			pre = w;
    		}
    	}
    

    然后 我是用循环模拟的(BFS)

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int MAXN = 1e6 + 1;
    const int MOD = 1e9 + 7; 
    vector<int> edge,V[MAXN][10],Q[MAXN];
    int ans[MAXN];
    bool vis[MAXN];
    int main()
    {
    	int i,n,m,cnt,j;
    	scanf("%d%d",&n,&m);
    	cnt = n;
    	for(i = 1;i <= m;i++)
    	{
    		int j,u,v,k = i;
    		scanf("%d%d",&u,&v);
    		edge.clear();
    		while(k) {edge.push_back(k % 10);k /= 10;}
    		int Size = edge.size(),pre = u;
    		for(j = Size - 1;j >= 0;j--)
    		{
    			int w = (j == 0? v:++cnt);
    			V[pre][edge[j]].push_back(w);
    			pre = w;
    		}
    		pre = v;
    		for(j = Size - 1;j >= 0;j--)
    		{
    			int w = (j == 0? u:++cnt);
    			V[pre][edge[j]].push_back(w);
    			pre = w;
    		}
    	}
    	int dep = 0;
    	Q[++dep].push_back(1);
    	vis[1] = 1;
    	for(i = 1;i <= dep;i++)
    		for(int w = 0;w < 10;w++)
    		{
    			bool able = 0;
    			for(j = 0;j < Q[i].size();j++)
    			{
    				int u = Q[i][j];
    				for(int k = 0;k < V[u][w].size();k++)
    				{
    					int v = V[u][w][k];
    					if(vis[v]) continue;
    					vis[v] = able = 1;
    					Q[dep + 1].push_back(v);
    					ans[v] = (ans[u] * 10ll + w) % MOD;
    				}
    			}
    			if(able) dep++;
    		}
       BFS
    	for(i = 2;i <= n;i++) printf("%d
    ",ans[i]);
    	return 0;
    }
    

    Sum up

    后面三道题我也不会了

    这次的题不难

    但我的分数很低 只做对了AB题

    值得反思

    我也还需要多打比赛 多练题

    把手感找到

  • 相关阅读:
    @ControllerAdvice + @ExceptionHandler 使用
    将博客搬至CSDN
    Docker pull网络错误
    Centos7.5安装Docker
    Oracle18c创建不带C##的用户
    Centos7.5静默安装Oracle18c
    nodeJs和JavaScript的异同
    maven项目引入本地包,不使用中央仓库
    java中把指数形式的数字转为正常形式显示
    validateJarFile jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class
  • 原文地址:https://www.cnblogs.com/resftlmuttmotw/p/11556630.html
Copyright © 2011-2022 走看看