模拟[懒得编号]考试总结
我要是不退役我一定把编号修上
考试经过
T1想了想觉得回了就写,T2确实很水就秒了,然后去看T3发现不会
我TM又不会李超树写个鬼啊 我怎么可能考场写线段树凸包啊于是写了暴力
然后全力肝T4,目标60分状压,然后开写,然后发现算重,然后改,然后继续算重……
重复n遍以后发现已经11:30了,于是开冲dfs,在52过了样例,发现只能跑\(n=9\),管那么多干啥啊,交了
交上去一看人傻了,T1程序里的assert(0)
没删,当场暴毙
最后看分,在T1没炸的情况下,50+100+50+25=225,发现没炸也啥也不是,退役分滚粗
T1.构造字符串
写挂的原因是只用并查集判断无解了,没用来构造答案就假了
发现可以转化成若干个\(a_i=b_i\)和\(a_i!=b_i\)的限制,所以对同类的缩到一起
如果一样的之间存在不等关系则无解,否则一次确定一类的取值,枚举全部取\(mex\)即可
#include
using namespace std;
#define int long long
const int N=1005;
int p[N][N],n,m,f[N];
inline void die(){puts("-1");exit(0);}
inline int find(int x)
{
if(f[x]!=x)f[x]=find(f[x]);
return f[x];
}
int ans[N];bool v[N],t[N][N];
vector pp[N];
signed main()
{
freopen("str.in","r",stdin);
freopen("str.out","w",stdout);
cin>>n>>m;
memset(p,-1,sizeof(p));
for(int i=1;i<=n;i++)p[i][i]=1;
for(int i=1;i<=m;i++)
{
int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);
for(int j=1;j<=z;j++)
{
if(!p[x][y])die();p[x][y]=p[y][x]=1;
x++;y++;
}
if(p[x][y]==1)die();p[x][y]=p[y][x]=0;
}
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(p[i][j]==1)f[find(j)]=find(i);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(p[i][j]==0)
{
int px=find(i),py=find(j);
if(px==py)die();
t[px][py]=t[py][px]=1;
}
}
for(int i=1;i<=n;i++)pp[find(i)].push_back(i);
memset(ans,-1,sizeof(ans));
for(int i=1;i<=n;i++)
{
if(ans[i]==-1)
{
int ff=find(i);memset(v,0,sizeof(v));int an;
for(int j=1;j<=n;j++)if(t[find(j)][ff]&&ans[find(j)]!=-1)v[ans[find(j)]]=1;
for(int j=0;j<=n;j++)if(!v[j]){an=j;break;}
for(int j=0;j
T2.寻宝
先用bfs把联通块缩起来,然后对100个门跑传递闭包,没门的不用管
一个询问如果在一块里直接可达,不在一块里如果可达就有解
#include
using namespace std;
#define int long long
#define pb push_back
#define pir pair
#define mp make_pair
const int N=50005;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
vector a[N],p[N];
char s[N];int n,m,k,qq,tot,cnt;
queue q;map mmp;
inline void bfs(int px,int py,int id)
{
q.push(mp(px,py));p[px][py]=id;
while(q.size())
{
int x=q.front().first,y=q.front().second;q.pop();
if(x>1&&a[x-1][y]==1&&p[x-1][y]==0)p[x-1][y]=id,q.push(mp(x-1,y));
if(y>1&&a[x][y-1]==1&&p[x][y-1]==0)p[x][y-1]=id,q.push(mp(x,y-1));
if(x>n>>m>>k>>qq;
for(int i=0;i<=m+1;i++)a[0].pb(0),p[0].pb(0);
for(int i=1;i<=n;i++)
{
a[i].pb(0);p[i].pb(0);scanf("%s",s+1);
for(int j=1;j<=m;j++)
{
if(s[j]=='#')a[i].pb(0);
else a[i].pb(1);
p[i].pb(0);
}
a[i].pb(0);p[i].pb(0);
}
for(int i=0;i<=m+1;i++)a[n+1].pb(0),p[n+1].pb(0);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
if(p[i][j]==0&&a[i][j]==1)bfs(i,j,++tot);
for(int i=1;i<=k;i++)
{
int x=read(),y=read(),xx=read(),yy=read();
int id1=p[x][y],id2=p[xx][yy],p1,p2;
if(mmp.find(id1)==mmp.end())mmp[id1]=++cnt,p1=cnt,b[p1][p1]=1;
else p1=mmp[id1];
if(mmp.find(id2)==mmp.end())mmp[id2]=++cnt,p2=cnt,b[p2][p2]=1;
else p2=mmp[id2];
b[p1][p2]=1;
}
for(int kk=1;kk<=cnt;kk++)for(int i=1;i<=cnt;i++)for(int j=1;j<=cnt;j++)
b[i][j]=b[i][j]|(b[i][kk]&b[kk][j]);
for(int i=1;i<=qq;i++)
{
int x=read(),y=read(),xx=read(),yy=read();
int id1=p[x][y],id2=p[xx][yy];
assert(id1&&id2);
if(id1==id2){puts("1");continue;}
if(mmp.find(id1)==mmp.end()||mmp.find(id2)==mmp.end()){puts("0");continue;}
int p1=mmp[id1],p2=mmp[id2];
if(b[p1][p2])puts("1");else puts("0");
}
return 0;
}
T3.序列
被称李超树模板题,于是滚去学了李超树
左右贡献相互独立,可以把柿子拆开,两个问题同理,以右端点为例
设\(sa_i=\sum_{j=1}^i a_j\),\(sb_i=\sum_{j=1}^ib_j\)
最优即\(\max_{1\leq l\leq r}\{(sa_{r}-sa_{l-1})-k(sb_{r}-sb_{l-1})\}\)
即\(sa_r-k\cdot sb_{r}+\max_{0\leq l
#include
using namespace std;
#define int long long
const int N=1000050;
int n,m,ans[N],pa[N],pb[N],suma[N],sumb[N];
struct line{int k,b;}a[N];
struct node{int id,k;};vector p[N];
struct tree{
int l,r,ma;
}tr[8*N];
inline int get(int id,int x){return a[id].k*x+a[id].b;}
inline double gett(int id1,int id2){return (1.0*a[id2].b-a[id1].b)/(1.0*a[id1].k-a[id2].k);}
void build(int id,int l,int r)
{
tr[id].l=l;tr[id].r=r;tr[id].ma=0;
if(l==r)return;int mid=(l+r)>>1;
build(id*2,l,mid);build(id*2+1,mid+1,r);
}
void add(int id,int v)
{
int mid=(tr[id].l+tr[id].r)>>1;
if(!tr[id].ma){tr[id].ma=v;return;}
int p1=get(tr[id].ma,tr[id].l),p2=get(tr[id].ma,tr[id].r),
p3=get(v,tr[id].l),p4=get(v,tr[id].r);
if(p3<=p1&&p4<=p2)return;
if(p3>=p1&&p4>=p2){tr[id].ma=v;return;}
double p=gett(tr[id].ma,v);
if(p3>=p1)
{
if(p<=mid)add(id*2,v);
else add(id*2+1,tr[id].ma),tr[id].ma=v;
}
else
{
if(p<=mid)add(id*2,tr[id].ma),tr[id].ma=v;
else add(id*2+1,v);
}
}
inline int clac(int x,int p1,int p2){if(p1>p2)swap(p1,p2);return (get(p1,x)>=get(p2,x))?p1:p2;}
int getans(int id,int p)
{
if(tr[id].l==tr[id].r)return tr[id].ma;
int mid=(tr[id].l+tr[id].r)>>1;
if(p<=mid)return clac(p,tr[id].ma,getans(id*2,p));
else return clac(p,tr[id].ma,getans(id*2+1,p));
}
signed main()
{
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
cin>>n>>m;build(1,-1e6,1e6);
for(int i=1;i<=n;i++)scanf("%lld%lld",&pa[i],&pb[i]);
for(int i=1;i<=m;i++)
{
int pp,k;scanf("%lld%lld",&pp,&k);
p[pp].push_back((node){i,k});
}
for(int i=1;i<=n;i++)suma[i]=pa[i]+suma[i-1],sumb[i]=sumb[i-1]+pb[i];
for(int i=1;i<=n;i++)
{
for(int j=0;j=1;i--)suma[i]=suma[i+1]+pa[i],sumb[i]=sumb[i+1]+pb[i];
build(1,-1e6,1e6);
for(int i=n;i>=1;i--)
{
for(int j=0;j
还是太菜了,无话可说
T4.构树
考虑多项式算法,好像有一个叫做扩展Cayley公式的东西:
被确定边分为大小为\(a_1,a_2,\cdots, a_m\)的连通块,则有\(n^{m-2}\prod {a_i}\)种生成树
显然是不会的,但可以知道结论
先咕
考试总结
没有停止挂分,没有想对正解,只能靠暴力度日
然而都是低档暴力基本没用,希望联赛不会是这样
还有四天,最后四场了,希望不留遗憾吧