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\)的中断施法可真是太草了