2020ICPC·小米 网络选拔赛第一场

2020ICPC·小米 网络选拔赛第一场

比赛分析

这场高手真的还是挺多的。我们队伍也实在是太拉垮了,有个队友实验未归。

我上来切了C、I 然后就没有过题了。

首先是J题,我的锅。我就想了几分钟就感觉是二维线段树,就直接开始写了,浪费快2hrs+,后来我突然发现我的复杂度少乘了个log,血亏。

队友的A也调了很久,一直没有过,据他所说,他被卡傻了。

队友2终于实验回来,做了个D,正解应该是边双还是啥的,反正他写个什么割点啥的。

总结

这场反正也进不了,但是暴露的问题非常多

第一,各自蛮干非常明显,交流少了。 有想法应该先和队友交流一下,尤其是这种网络赛,多线程可敲的时候,反而不要忽视单机子的这个重要流程。像我的二维线段树,如果讲清楚,队友,或者我自己都可能看到问题,简单的dp就不会做成数据结构题

第二,题意方面。每个人优先读一道题,然后翻译成中文,再让队友带着中文去再读一遍题意,检查是否理解错误。比如I题,我一开始读错了,队友准备写的时候,提醒了一下我,我才发现错误。以后要保证每道题目至少要被反复读过两遍。

第三,要注意看榜单信息。如果有些题很多队过了,或者说,一些题很快被切了,那么它极大概率不是比较复杂的数据结构题,以及难的数论。。。

第四,是勤换思路。有些时候想题目不要局限于一种算法中,要果敢放弃。思路或者题目什么时候该进行舍弃嘞?

如果思路想不通到15min,并且此题可做,那么换思路

如果某个题花费30min思考没有突破,先放下,去读题

C 简单签到

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
using namespace std;
#define INF 0x3f3f3f3f
#define max(a,b) (a>b ? a:b)
#define min(a,b) (a<b ? a:b)
#define swap(a,b) (a^=b^=a^=b)
#define maxn 105
#define minn -105
#define ll long long int
#define ull unsigned long long int
#define uint unsigned int
inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'|ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}
int main()
{
    string s;
    cin>>s;
    int ans=0;
    int len=s.size();
    for(int i=0;i<len;i++)
    {
        if(s[i]=='w')ans++;
        if(i)
        {
            if((s[i]=='w')&&(s[i-1]=='w'))ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}


I dfs 记忆化

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define INF 0x3f3f3f3f
#define max(a,b) (a>b ? a:b)
#define min(a,b) (a<b ? a:b)
#define swap(a,b) (a^=b^=a^=b)
#define maxn 1405
#define minn -105
#define ll long long int
#define ull unsigned long long int
#define uint unsigned int
inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'|ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}
int n,m;


char a[maxn][maxn];
bool been[maxn][maxn];
int out[maxn][maxn];

bool dfs(int x,int y)
{
    if(x==0||y==0||x==n+1||y==m+1)
    {
        return 1;
    }
    if(been[x][y])
    {
        return out[x][y];
    }
    been[x][y]=1;
    bool cur=0;
    if(a[x][y]=='W')cur=dfs(x-1,y);
    if(a[x][y]=='A')cur=dfs(x,y-1);
    if(a[x][y]=='S')cur=dfs(x+1,y);
    if(a[x][y]=='D')cur=dfs(x,y+1);
    out[x][y]=cur;
    return cur;

}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(!been[i][j])
            {
                dfs(i,j);
            }
            if(out[i][j]==1)ans++;

        }


    cout<<ans<<endl;
    return 0;
}

J dp

维护二维前缀和就好了,没必要实现每次区间的维护。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define INF 0x3f3f3f3f
#define max(a,b) (a>b ? a:b)
#define min(a,b) (a<b ? a:b)
#define swap(a,b) (a^=b^=a^=b)
#define maxn 1305
#define minn -105
#define ll long long int
#define ull unsigned long long int
#define uint unsigned int
inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'|ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}
int a[maxn][maxn];
int pre[maxn][maxn];
int give[maxn][maxn];
int n,m,x,y;
string ac="^_^
";
string wa="QAQ
";
void solve()
{
    cin>>n>>m>>x>>y;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            a[i][j]=read();

        }
    int cur=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            //give[i][j]=0;
            int cur=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1];
            pre[i][j]=cur;
            cur+=pre[max(0,i-x)][max(0,j-y)]-pre[i][max(0,j-y)]-pre[max(0,i-x)][j];
            if(i>=n+2-x||j>=m+2-y)
            {
                if(a[i][j]!=cur)
                {
                    cout<<wa;
                    return;
                }
                continue;
            }
            else
            {
                if(cur>a[i][j])
                {
                    cout<<wa;
                    return;
                }
                pre[i][j]+=a[i][j]-cur;
            }
        }
    cout<<ac;

}
int main()
{
    int _t;
    cin>>_t;
    while(_t--)solve();
    return 0;
}

D

点双联通分量,预处理出每个点所属的双联通分量个数,答案为联通块数减去1加上所属的双联通块个数(预处理孤立点,所属的双联通块个数为0)

#include<bits/stdc++.h>
using namespace std;
struct tedge{
	int w,next;
}e[1000010];
int l[500010],dfn[500010],low[500010],st[500010],del[500010],gu[500010],d[500010];
int cnt,tot,top,cnt1,n,m,root,sum;
vector <int> ve[500010];
void add(int x,int y)
{
	e[++cnt].w=y;
	e[cnt].next=l[x];
	l[x]=cnt;
}
void tarjan(int x)
{
	dfn[x]=low[x]=++tot;
	st[++top]=x;
	if(x==root&&l[x]==0)
	{
		ve[++cnt1].push_back(x);
		gu[x]=1;
		return;
	}
	for(int i=l[x];i;i=e[i].next)
	{
		int v=e[i].w;
		if(!dfn[v])
		{
			tarjan(v);
			low[x]=min(low[x],low[v]);
			if(low[v]>=dfn[x])
			{
				cnt1++;
				int z;
				do{
					z=st[top--];
					ve[cnt1].push_back(z);
				}while(z!=v);
				ve[cnt1].push_back(x);
			}
		}
		else
		low[x]=min(low[x],dfn[v]);
	}	
}
int main()
{
	cin>>n>>m;
	int x,y;
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y;
		if(x==y)
		continue;
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;i++)
	if(!dfn[i])
	{
		sum++;
		root=i;
		tarjan(i);
	}
	for(int i=1;i<=cnt1;i++)
    for(int j=0; j<ve[i].size();j++)
    d[ve[i][j]]++;
    for(int i=1;i<=n;i++)
    {
    	if(gu[i])
    	cout<<sum-1<<" ";
    	else
    	cout<<sum-1+d[i]<<" ";
	}
    return 0;
}

A

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int a[300010],n,m,x;
int f[10000010],bj[10000010],prime[10000100],tot,f1[10000010]; 
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		f1[a[i]]++;
		f[a[i]]++;
	}
	sort(a+1,a+n+1);
	int maxn=a[n];
	int ans=0;
	for(int j=2;j<=maxn;j++)
	{
		if(!bj[j]){
			prime[++tot]=j;f[j]+=f[1];
		}
		for(int i=1;i<=tot;i++)
		{
			if(j*prime[i]<=maxn)
			{
				bj[j*prime[i]]=1;
				f[j*prime[i]]=max(f[j*prime[i]],f1[j*prime[i]]+max(f[j],f[prime[i]]));
			}
			else break;
		}
		ans=max(ans,f[j]);
	}
	cout<<ans;
	return 0;
}
原文地址:https://www.cnblogs.com/et3-tsy/p/13879472.html