模拟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,每次新增一批点,然后进行维护,在到分界线的时候统计答案
后面是并查集,每次合并的时候维护他的三种权值,分别是点数和两个边数,傻孩子没看题解瞎分类讨论,把人整自闭了
image
点是很好统计的,就是\(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.不要轻易否掉某一种思路,多思考

posted @ 2021-09-21 06:13  D'A'T  阅读(41)  评论(0)    收藏  举报