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="^_^\n";
string wa="QAQ\n";
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;
}