2021.5.9模拟赛赛后总结

这题真的是震惊我一整年

好了不多说什么了,看数据差不多就打暴力吧,拿分才是关键,别老瞎想这想那,最后屁用没有。

T1:teams

其实教练的本意是要考字符串哈希的,可他没想到,数据太弱导致什么乱搞都能过得去。

首先是最 ** 的,直接用\(set\)判重,然后大爆搜。

大爆搜 甚至没有一丁点剪枝。

具体长这样的,我相信只要脑子没问题都能看得懂:


//#define LawrenceSivan

#include<bits/stdc++.h>
using namespace std;

set <string> q;

int k,ans=-1e9;
bool vis[21];

struct q{
	string a;
	string b;
	string c; 
}s[25];

void dfs(int x,int step){
	if(step>ans){
		ans=step;
	}
	for(int i=1;i<=k;i++){
		if(!vis[i]&&q.find(s[i].a)==q.end()&&q.find(s[i].b)==q.end()&&q.find(s[i].c)==q.end()){
			q.insert(s[i].a);
			q.insert(s[i].b);
			q.insert(s[i].c);
			vis[i]=1;
			dfs(i,step+1);
		}
	}
}
void clear(){
	memset(vis,0,sizeof(vis));
	q.clear();
}
int main(){
#ifdef LawrenceSivan
	freopen("teams.in","r",stdin);
	freopen("teams.out","w",stdout);
#endif	
	scanf("%d",&k);
	for(int i=1;i<=k;i++){
		cin>>s[i].a>>s[i].b>>s[i].c;
	}
	
	for(int i=1;i<=k;i++){
		q.insert(s[i].a);
		q.insert(s[i].b);
		q.insert(s[i].c);
		dfs(i,1);
		clear();
	}
	cout<<ans;
	
	return 0;
}

\(std\)是这样的(也许hehe这个数组名就是用来嘲讽我的/kk):

#include <stdio.h>
#include <string.h>
#define MOD 352197
int hehe[60][4], vis[400010], k, ans;
char list[356000][55], t[55];

int hash(char s[]) {
    int i = 0, h = 0;
    while (s[i]) {
        h = (h * 131 + (int)s[i]) % MOD;
        i++;
    }
    while (list[h][0] != 0 && strcmp(list[h], s) != 0) {
        h++;
        if (h >= MOD)
            h = 0;
    }
    strcpy(list[h], s);
    return h;
}

void dfs(int i, int num) {
	int j, flag = 0;
	if (i == k + 1) {
		if (num > ans) ans = num;
		return;
	}
	dfs(i + 1, num);
	for (j = 1; j <= 3; j++) {
		if (vis[hehe[i][j]]) 
			return;
	}
	for (j = 1; j <= 3; j++) {
		vis[hehe[i][j]] = 1;
	}
	dfs(i + 1, num + 1);
	for (j = 1; j <= 3; j++) {
		vis[hehe[i][j]] = 0;
	}
}

int main() {
	//freopen("teams.in","r",stdin);
	//freopen("teams.out","w",stdout);
	int i, j;
	scanf("%d", &k);
	for (i = 1; i <= k; i++) {
		for (j = 1; j <= 3; j++) {
			scanf("%s", t);
			hehe[i][j] = hash(t);
		}	
	}
	dfs(1, 0);
	printf("%d\n", ans);
	return 0;
}

大概一开始是觉得字符串哈希然后突然想到了网络流然后想试一试?最后也没搞出来)

T2:zoo

\(NOI \ 2014\)原题

是个\(KMP\)的好题,深入研究这道题确实可以让自己的\(KMP\)脱胎换骨。

首先看\(num\)的定义,就是不重叠的公共前后缀的个数,或者理解为跳几次才能跳到开头。

于是我们可以搞出一个\(num[i]=num[next[i]]+1\)

然后我们看过题,明白了\(next\)数组的另外一种含义:“对于字符串\(S\)的前\(i\)个字符构成的子串,既是它的后缀又是它的前缀的字符串中(它本身除外),最长的长度记作\(next[i]\)。”

就是说\(next\)记录的是一个最大值,而\(num\)记录的是一个数量。

于是我们就可以在求解\(next\)的同时求一下可重叠的num数组(这个时候其实是个假的,因为它可重叠,而我们需要不能重叠的,最后我们去除一下就行了)

接下来的题就是如何去除重复部分:

\(next\)有一个性质:\(next[i]<i\)

于是我们跳\(next\)直到\(j \le i/2\),然后更新答案就行了。

//#define LawrenceSivan

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define re register
const int maxn=1e6+5;
#define INF 0x3f3f3f3f
const int mod=1e9+7;

int T;

int nxt[maxn],num[maxn],len;
ll cnt;
char a[maxn];

inline void get_next(){
	for(re int i=2,j=0;i<=len;i++){
		while(j&&a[j+1]!=a[i])j=nxt[j];
		if(a[j+1]==a[i])j++;
		nxt[i]=j;
		num[i]=num[j]+1;
	}
}

inline void get_num(){
	for(re int i=2,j=0;i<=len;i++){
		while(j&&a[j+1]!=a[i])j=nxt[j];
		if(a[j+1]==a[i])j++;
		while(j*2>i) j=nxt[j];
        (cnt*=(ll)(num[j]+1))%=mod;
	}
}

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
}

int main(){
#ifdef LawrenceSivan
    freopen("zoo.in","r",stdin);
    freopen("zoo.out","w",stdout);
#endif

	T=read();
	while(T--){
		cin>>a+1;
		len=strlen(a+1);
		memset(nxt,0,sizeof(nxt));
		
		num[0]=0,num[1]=1;
		get_next();
		
		cnt=1;
		get_num();
		
		printf("%lld\n",cnt);
	}

	return 0;
}

T3:demon

凸包裸题?
(因为考场上我嘴欠直接说出了做法导致这玩意被A穿了)

貌似其实也有很多人会做?

这不废话吗求个多边形面积这么垃圾的玩意谁不会做

直接读进去搞个凸包然后差积大力搞面积就好了

代码也很简单:

//#define LawrenceSivan

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define re register
const int maxn=1e4+5;
#define INF 0x3f3f3f3f
#define double int

int n,top1,top2,cnt;
ll ans;

struct node{
	double x,y;
	inline bool operator < (node a)const{return x<a.x||(x==a.x&&y<a.y);}
}p[maxn],st1[maxn],st2[maxn],st3[maxn];

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
    return x*f;
}

inline double v_pro(node a,node b,node c){
	return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}

inline double S(){
	double res=0;
	for(re int i=2;i<cnt;i++) res+=v_pro(st3[1],st3[i],st3[i+1]);
	return res/2;
}

int main(){
#ifdef LawrenceSivan
    freopen("demon.in","r",stdin);
    freopen("demon.out","w",stdout);
#endif
	n=read();
	for(re int i=1;i<=n;i++){
		double x,y;
		scanf("%d%d",&x,&y);
		p[i].x=x;
		p[i].y=y;
	}
	
	sort(p+1,p+1+n);
	st1[0]=p[1];
	
	for(re int i=1;i<=n;i++){
		while(top1&&v_pro(st1[top1],st1[top1-1],p[i])>=0)--top1;
		st1[++top1]=p[i];
	}
//    for(re int i=1;i<=top1;i++){
//		cout<<st1[i].x<<" "<<st1[i].y<<endl;
//	}
    
    
    
   	st2[top2]=p[n];
	for(re int i=n-1;i;i--){
		while(top2&&v_pro(st2[top2],st2[top2-1],p[i])>=0)--top2;
		st2[++top2]=p[i];	
	} 
//	for(re int i=1;i<=top2;i++){
//		cout<<st2[i].x<<" "<<st2[i].y<<endl;
//	}

	cnt=top1+top2;
	for(re int i=1;i<=cnt;i++){
		if(i<=top1)st3[i]=st1[i];
		else st3[i]=st2[i-top1];
	}
	
//	for(re int i=1;i<=cnt;i++){
//		cout<<st3[i].x<<" "<<st3[i].y<<endl;
//	}

	
	ans=(ll)S();
	
	printf("%lld\n",ans/50);

	return 0;
}


后记

\(llf\)的中断施法可真是太草了

posted @ 2021-05-10 18:34  LawrenceSivan  阅读(55)  评论(0编辑  收藏  举报