Time:2018.4.3 18:00 - 22:00
A Artwork solved by ym solved by czh
题意
给一个n×m一个网格,有q个询问,每次询问有两个点坐标,表示从第一个点到第二个点都被标记(这两个点x/ y相同),对于q个询问,每次输出网格共被分成几个区域(1<=n,m<=1e3,q<=10000)
分析
比赛的时候对于每个q直接bfs不出意外的tle的起不来,没有好的思路,死掉
赛后:联通块应该想到并查集来解决
对询问倒着作,并查集维护联通块即可
hash函数写反错了一年才找出来 by ym
赛后学长指点了一下,但写出来后超时,原来是并查集路径压缩错了,以前用的路径压缩都不是很快 by czh
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1000+7;
const int maxm = 1e6+200;
int dx[5]={1,-1,0,0};
int dy[5]={0,0,-1,1};
int n,m,q;
int num[maxn][maxn];
int answer[maxm];
int fa[maxm];
int x1[maxn*10], y1[maxn*10], x2[maxn*10], y2[maxn*10];
void init()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
fa[(i-1)*m+j]=(i-1)*m+j;
}
}
}
int findfa(int x)
{
if(x==fa[x])
return x;
else
return fa[x]=findfa(fa[x]);
}
int tot=0;
void join(int x,int y)
{
int xx=findfa(x);
int yy=findfa(y);
if(xx!=yy)
{
fa[yy]=xx;
tot--;
}
}
void ok(int x,int y)
{
for(int i=0;i<4;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(xx>=1 && xx<=n && yy>=1 && yy<=m && num[xx][yy]==0)
{
join((xx-1)*(m)+yy, (x-1)*m+y);
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &q);
init();
for(int i=1;i<=q;i++)
{
scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
if(x1[i]==x2[i])
{
for(int j=y1[i];j<=y2[i];j++)
{
num[x1[i]][j]++;
}
}
else
{
for(int j=x1[i];j<=x2[i];j++)
{
num[j][y1[i]]++;
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(num[i][j]==0)
{
ok(i,j);
tot++;
}
}
}
for(int i=q;i>=1;i--)
{
answer[i]=tot;
if(x1[i]==x2[i])
{
for(int j=y1[i];j<=y2[i];j++)
{
--num[x1[i]][j];
if(num[x1[i]][j]==0)
{
tot++;
ok(x1[i],j);
}
}
}
else
{
for(int j=x1[i];j<=x2[i];j++)
{
--num[j][y1[i]];
if(num[j][y1[i]]==0)
{
tot++;
ok(j,y1[i]);
}
}
}
}
for(int i=1;i<=q;i++) printf("%d
", answer[i]);
return 0;
}
B Bless You Autocorrect! solved by none
题意
给一本有n个单词的词库具有自动补全功能,优先级从高到低,q个询问,问每个询问的单词的最小输入(1<=n<=1e5,1<=q<=1e5)
注意:不存在一个单词由多个单词共同构成
分析
将所有单词构成一颗字典树,根据优先级建好边后,在树上跑个tree dp
目前码不出来,留坑
zls代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
struct Node
{
int nxt[26];
int jump;
int fa;
};
Node trie[2000005];
int n,m;
string s[100005];
int en[100005];
int dist[2000005];
queue<int> q;
int num=0;
int insert(string s)
{
int now=0,dq;
for (int i=0;i<s.size();++i)
{
int dq=s[i]-'a';
if (trie[now].nxt[dq]==-1)
{
++num;trie[now].nxt[dq]=num;
trie[num].fa=now;
for (int j=0;j<26;++j) trie[num].nxt[j]=-1;
trie[num].jump=-1;
add(now,num,1);
add(num,now,1);
}
now=trie[now].nxt[dq];
}
return now;
}
void addedge(string s,int en)
{
int now=0,dq;
for (int i=0;i<s.size();++i)
{
int dq=s[i]-'a';
if (trie[now].jump==-1)
{
add(now,en,1);
trie[now].jump=en;
}
now=trie[now].nxt[dq];
}
if (trie[now].jump==-1)
{
trie[now].jump=en;
add(now,en,1);
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i) cin>>s[i];
for (int i=0;i<26;++i) trie[0].nxt[i]=-1;
trie[0].jump=0,trie[0].fa=-1;
for (int i=1;i<=n;++i)
{
int tmp=insert(s[i]);
addedge(s[i],tmp);
}
for (int i=1;i<=m;++i)
{
cin>>s[0];
en[i]=insert(s[0]);
}
for (int i=0;i<=num;++i) dist[i]=1e9;
dist[0]=0;
while (!q.empty()) q.pop();
q.push(0);
trie[0].jump=-1;
while (!q.empty())
{
int x=q.front();q.pop();
for (int i=0;i<26;++i) if (trie[x].nxt[i]!=-1)
{
int y=trie[x].nxt[i];
if (dist[y]!=1e9) continue;
dist[y]=dist[x]+1;
q.push(y);
}
if (trie[x].fa!=-1)
{
int y=trie[x].fa;
if (dist[y]==1e9){
dist[y]=dist[x]+1;
q.push(y);}
}
if (trie[x].jump!=-1)
{
int y=trie[x].jump;
if (dist[y]==1e9) {
dist[y]=dist[x]+1;
q.push(y);}
}
}
for (int i=1;i<=m;++i) printf("%d
",dist[en[i]]);
return 0;
}
C Card Hand Sorting solved by czh
题意
有n张牌排成一行,每张牌两个属性,第一个数字/字母代表它在这一类的rank,后一个字母代表它的种类,共有13个rank和4种牌,现要求同种牌必须放在相邻位置,每种牌内部是有序的,问最少需要移动几次(移动是任意的)(n<=52)
分析
ym:暴力枚举+maskdp,待补
czh:注意到n最大为52,枚举花色的顺序和花色内的顺序,然后求最大子序列
#include<bits/stdc++.h>
using namespace std;
map<char,int>mp;
char color[60],a[3];
int pe[4]={1,2,3,4},ind[60],n,num[60];
map<char,int>ma;
int dp[60];
int LIS()
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
dp[i]=1;
int maxx=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)
{
if(num[i]>num[j])
dp[i]=max(dp[i],dp[j]+1);
}
maxx=max(maxx,dp[i]);
}
return maxx;
}
int main()
{
ma['s']=0;ma['h']=1;ma['d']=2;ma['c']=3;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%s",a);
if(a[0]>='0'&&a[0]<='9')
ind[i]=a[0]-'0';
else if(a[0]=='T')ind[i]=10;
else if(a[0]=='J')ind[i]=11;
else if(a[0]=='Q')ind[i]=12;
else if(a[0]=='K')ind[i]=13;
else if(a[0]=='A')ind[i]=14;
color[i]=a[1];
}
int ans=0;
do{
for(int i=0;i<16;i++)
{
for(int j=1;j<=n;j++)
{
num[j]=pe[ma[color[j]]]*1000;
if(((1<<ma[color[j]])&i)==0)
num[j]-=ind[j];
else
num[j]+=ind[j];
}
ans=max(ans,LIS());
}
}while(next_permutation(pe,pe+4));
cout<<n-ans<<endl;
}
D Daydreaming Stockbroker solved by ym solved by czh
题意
给你n天的物价,初始有100元,库存量最大不能超过1e5,问最后做多可以有多少钱
对比:http://codeforces.com/contest/867/problem/E
分析
此题感觉能挣钱就买卖,低进高出即可
CF867E,一天只能买或者卖
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[370];
int main()
{
int n;
scanf("%d", &n);
for(int i=1;i<=n;i++) scanf("%d", &a[i]);
ll sum=100;
for(int i=1;i<n;i++)
{
if(a[i+1]>a[i])
{
ll num=min(sum/a[i], 100000LL);
sum=sum-num*a[i]+num*a[i+1];
}
}
printf("%lld
", sum);
return 0;
}
E Exponial
数论题
F Fleecing the Raffle solved by czh&ym
题意
现在有n个人抽奖,共有p个奖,现在可以将任意数量自己的名字放入箱子里,问自己最大的中奖概率
分析
设添加x个自己,则中奖概率为 C(x,1) * C(n,p-1) / C(n+x,p)
组合式推一下,化简一下不难看出规律,暴力找最大值即可
G Game Rank solved by czh solved by ym
题意
模拟题
分析
ym:按题意模拟即可
czh:题目很绕,没有很快理解出题意 by czh
H Highest Tower
DIfficult
I Interception
DIfficult
J Jumbled Compass solved by czh solved by ym
签到题
K Keeping the Dogs Apart
DIfficult
Summary
Ym:训练的时候很困=_=,没状态,还读错题了,坑了,和学弟一起训练体验很好呀
读题能力不行,需要及时背单词,提升读题能力
提升思维能力
Czh: 英语水平要求很高,一两个关键单词认错往往这题就过不了