模拟57 考试总结
果然自己只配做水题啊
考试经过
晚半小时开题,因为沉迷改题推式子,根本看不懂题解
T1好家伙大模拟,细节搞了半天,T2写了个dp发现越看越不对,最后直接贪心模拟了。。。
T3不太会写了40,想到了bitset,因为自己是智障算错复杂度+没看明白数据限制就没打,痛失\(60pts\)
T4没咋看懂,发现不会暴力,想了半天最终被迫输出样例
最后5分钟发现T1的bug,暗自庆幸,以为自己肯定能A
结果:90+100+40+0=230 ,本地rk16,综合60开外。。。
T1还是挂了,死在最后的点上,T2暴力竟然过了,意外
T3一众AC,wtz差点AK,%%%
T1.2A
大模拟,注意最后可能还有点号,情况要想全
#include <bits/stdc++.h>
using namespace std;
#define int long long
char s[50];
char ss[5][35];int tot=0;
char ans[35],ga=0;
inline void gan(int i)
{
ans[++ga]='2',ans[++ga]='5',ans[++ga]='5';
if(i!=4)ans[++ga]='.';
}
inline void gann(int i,int l)
{
for(int j=1;j<=l;j++)ans[++ga]=ss[i][j];
if(i!=4)ans[++ga]='.';
}
inline int change(int i)
{
char pp[35];memset(pp,0,sizeof(pp));
int l=strlen(ss[i]+1);
for(int j=1;j<=l;j++)pp[j]=ss[i][j];
int p=1;while(pp[p]=='0'&&p!=l)p++;
int tmp=0;
for(int j=p;j<=l;j++)ss[i][++tmp]=pp[j];
return l-p+1;
}
signed main()
{
freopen("ip.in","r",stdin);
freopen("ip.out","w",stdout);
scanf("%s",s+1);bool flag=1;
int num=1,n=strlen(s+1);bool dig=1;
for(int i=1;i<=n;i++)
{
if(s[i]>='0'&&s[i]<='9')
{
ss[num][++tot]=s[i];
dig=0;
continue;
}
else
{
if(tot)num++,tot=0;
if(num>4)dig=1;
if(dig){flag=0;continue;}
if(s[i]=='.'){dig=1;continue;}
flag=0;continue;
}
}
for(int i=1;i<=4;i++)
{
int l=strlen(ss[i]+1);
if(l!=1&&ss[i][1]=='0')l=change(i),flag=0;
if(l>3){flag=0;gan(i);continue;}
if(l<=2){gann(i,l);continue;}
int p=(int)(ss[i][1]-'0')*100+(int)(ss[i][2]-'0')*10+(int)(ss[i][3]-'0');
if(p>255){flag=0;gan(i);continue;}
gann(i,l);
}
if(flag)puts("YES");
else puts("NO"),printf("%s\n",ans+1);
return 0;
}
T2.2B
每次遇到AP直接删,一定最优
完全可以\(O(n)\)的栈,不过我写了个\(n^2\)的模拟,就不放出来了吧。。。
话说一共不到100ms就离谱
T3.2C
前面两个很好满足,用map记一下就行
第三个限制可以对每个字符串开一个1000位的bitset表示他的祖先集合,注意不包括他本身
对于第三个,一个声明不合法当且仅当存在两个祖先串\(s1\),\(s2\),满足\(bit_{s1,s2}==0,bit_{s2,s1}==0,bit_{s1}andbit_{s2}!=0\)
理论复杂度\(n^3\),算上bitset的优化已经可过,事实上上界极松,暴力\(n^4\)都能过。。。
正解似乎舍弃了不合法情况,做到了$n^2\log $,但时间差别似乎不大
#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
const int N=1050;
char s[12],b[N][12],op[2];
ull ha[12],hb[N][12],p[15];
int ll[N];
struct node{
int from,to,next;
}a[2*N];
int head[N],mm=1;
inline void add(int x,int y)
{
a[mm].from=x;a[mm].to=y;
a[mm].next=head[x];head[x]=mm++;
}
unordered_map <ull,int> mp;int tot;
bitset <N> bit[N];
signed main()
{
freopen("class.in","r",stdin);
freopen("class.out","w",stdout);
int n;cin>>n;
p[0]=1;for(int i=1;i<=12;i++)p[i]=p[i-1]*13331;
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);int num=1;
int l=strlen(s+1);
for(int j=1;j<=l;j++)ha[j]=ha[j-1]*13331+(s[j]-'a'+1);
scanf("%s",b[0]+1);
while(b[num-1][1]!=';')
{
scanf("%s",b[num]+1);
ll[num]=strlen(b[num]+1);
for(int j=1;j<=ll[num];j++)hb[num][j]=hb[num][j-1]*13331+(b[num][j]-'a'+1);
num++;
}
num-=2;bool flag=0;
//cout<<num<<endl;
if(mp.find(ha[l])!=mp.end()){puts("greska");continue;}
for(int j=1;j<=num;j++)if(mp.find(hb[j][ll[j]])==mp.end()){flag=1;break;}
if(flag){puts("greska");continue;}
for(int j=1;j<=num;j++)
{
int id1=mp[hb[j][ll[j]]];
for(int k=j+1;k<=num;k++)
{
int id2=mp[hb[k][ll[k]]];
if((bit[id1][id2]==0)&&(bit[id2][id1]==0)&&((bit[id1]&bit[id2])!=0))
{flag=1;break;}
}
if(flag)break;
}
if(flag){puts("greska");continue;}
mp.insert(make_pair(ha[l],++tot));puts("ok");
for(int j=1;j<=num;j++)
{
int id=mp[hb[j][ll[j]]];bit[tot][id]=1;
bit[tot]|=bit[id];
}
}
return 0;
}
T4.2D
神仙题,是不会的思路
首先一个性质,\(k\)大的图一定是\(k\)小的图的子图
所以可以先确定\(k\)的最大值,然后依次扩展,更新贡献,似乎和这一场的T2有点像
所以现在的问题是如何确定这个最大的\(k\)
首先\(k\)的上限是每个节点的度数,但显然比这要小,考虑更新迭代,先按照度数从小到大排序,然后对于一个点扫出边,如果对面的点的度数大于它,就让对面的点度数减一,依次类推
我用了堆实现,但实际要用桶排保证线性,题解大概是通过交换元素,处理分界线来保证有序,嫌麻烦没打
然后对于每个k,每次新增一批点,然后进行维护,在到分界线的时候统计答案
后面是并查集,每次合并的时候维护他的三种权值,分别是点数和两个边数,傻孩子没看题解瞎分类讨论,把人整自闭了

点是很好统计的,就是\(size\),边要保证补充不漏,这里给每个点一个新的\(rank\),按原来的权值为第一关键字,节点编号为第二关键字比较就好,实际上也可以每次现比较,对于新加入的一个点\(x\),先扫\(x\)的所有出边,把能合并的先合并上,然后再扫一遍统计贡献。
\(m\)要保证同一条边不会被算两次,所以上面按照节点编号又比较了一次
\(b\)尤其注意不要算重,前面暴力合并可能会把一些本来不是外连边的东西合并上去,所以要减去
然后大概就完了,卡常卡了\(998244353\)年,感谢fread救我狗命
#include <bits/stdc++.h>
using namespace std;
//#define int long long
const int N=1000050;
#define gc if(++ip==ie)fread(ip=buf,1,SZ,stdin)
const int SZ=1<<19;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int read(){
gc;while(*ip<'-')gc;
bool f=*ip=='-';if(f)gc;
int x=*ip&15;gc;
while(*ip>'-'){x*=10;x+=*ip&15;gc;}
return f?-x:x;
}
struct node{
int from,to,next;
}a[2*N];
int head[N],mm=1;
inline void add(int x,int y)
{
a[mm].from=x;a[mm].to=y;
a[mm].next=head[x];head[x]=mm++;
}
int n,m,du[N];long long vn,vm,vb;
priority_queue <pair<int,int > > q;
struct nd{
int id,rank;
friend bool operator <(nd x,nd y)
{
if(x.rank!=y.rank)return x.rank>y.rank;
return x.id>y.id;
}
}p[N];
int f[N],sn[N],sm[N],sb[N];
bool v[N];
inline int find(int x)
{
if(f[x]!=x)f[x]=find(f[x]);
return f[x];
}
signed main()
{
freopen("kdgraph.in","r",stdin);
freopen("kdgraph.out","w",stdout);
cin>>n>>m>>vm>>vn>>vb;
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
add(x,y);add(y,x);
du[x]++;du[y]++;
}
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=n;i++)q.push(make_pair(-du[i],i));
while(q.size())
{
int x=q.top().second,w=-q.top().first;
q.pop();if(w!=du[x])continue;
for(int i=head[x];i;i=a[i].next)
{
int y=a[i].to;
if(du[y]<=du[x])continue;
du[y]--,q.push(make_pair(-du[y],y));
}
}
for(int i=1;i<=n;i++)p[i].id=i,p[i].rank=du[i];
sort(p+1,p+1+n);
int k=0;long long ans=-1e18;
for(int t=1;t<=n;t++)
{
int x=p[t].id,w=p[t].rank,fx=find(x);
if(!w)break;
for(int i=head[x];i;i=a[i].next)
{
int y=a[i].to,fy=find(y);
if(du[y]<du[x])continue;
if(fy==fx)continue;
f[fy]=fx;sn[fx]+=sn[fy];sm[fx]+=sm[fy];sb[fx]+=sb[fy];
}
sn[fx]++;
for(int i=head[x];i;i=a[i].next)
{
int y=a[i].to,fy=find(y);
if(du[y]>du[x]||(du[y]==du[x]&&y>x))sm[fx]++,sb[fx]--;
if(du[y]<du[x]||(du[y]==du[x]&&y<x))sb[fx]++;
}
if(p[t+1].rank!=p[t].rank)
{
for(int j=t;j>=1;j--)
{
if(p[j].rank!=w)continue;
int y=p[j].id,fy=find(y);
if(!v[fy])
{
long long an=sm[fy]*vm-sn[fy]*vn+sb[fy]*vb;
if(an<ans)continue;
if(an==ans)k=max(k,w);
else ans=an,k=w;
v[fy]=1;
}
}
}
}
cout<<k<<" "<<ans<<endl;
return 0;
}
考试总结
1.细节要注意,考虑各种情况
2.看题一定要细,不要漏掉某些重要内容,造成错误理解
3.不要轻易否掉某一种思路,多思考

浙公网安备 33010602011771号