总之就是 | ZROI CSP联测 Day5
「0.0」序章
怎么说呢,虽然这次打的分数差强人意,但是还是挂了很多不该挂的分,毕竟高达 95~125 pts(
对题目的描述格式又有了一点改变(?)
没有 NOIP21D5 题解不是我咕掉了,而是比赛推迟了。
缺省源:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <queue>
#define Heriko return
#define Deltana 0
#define Romanno 1
#define S signed
#define LL long long
#define R register
#define I inline
#define CI const int
#define mst(a, b) memset(a, b, sizeof(a))
#define ON std::ios::sync_with_stdio(false);cin.tie(0)
#define Files() freopen("RNMTQ.in","r",stdin);freopen("RNMTQ.out","w",stdout)
using namespace std;
template<typename J>
I void fr(J &x)
{
short f(1);x=0;char c=getchar();
while(c<'0' or c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while (c>='0' and c<='9')
{
x=(x<<3)+(x<<1)+(c^=48);
c=getchar();
}
x*=f;
}
template<typename J>
I void fw(J x,bool k)
{
if(x<0) x=-x,putchar('-');
static short stak[35];short top(0);
do
{
stak[top++]=x%10;
x/=10;
}
while(x);
while(top) putchar(stak[--top]+'0');
k?puts(""):putchar(' ');
}
把T3 用到的
queue
和 T4 用到的vector
和set
加进去了w.
「1.0」30の游戏
原题目:「A. 游戏」
开场手速题,机房和场上最快的都是 2 min 左右,我稍微慢了点,加上延迟用了 8 min.
「1.1」题目简述
给出数字 \(N\),求问将 \(N\) 的各个数位上的数字进行调换顺序之后能得到的最大的 \(30\) 的倍数是多少。
\(N \le 10^{10^5}.\)
「1.2」思路简述
上过小学数学课的都知道,\(3\) 的倍数各个数位相加之和也为 \(3\) 的倍数,而 \(30 = 3 \times 10\),所以我们只需要再判断一下有没有出现原数位中 \(0\) 即可。
「1.3」Code
CI MXX(1e5+1);
char c[MXX];
LL mp[10];
LL sum;
S main()
{
Files();
scanf("%s",c+1);
int n(strlen(c+1));
for(int i(1);i<=n;++i) ++mp[c[i]-'0'],sum+=(c[i]-'0');
if(!mp[0])
{
puts("-1");
Heriko Deltana;
}
if(sum%3!=0)
{
puts("-1");
Heriko Deltana;
}
for(int i(9);i>=0;--i)
for(int j(mp[i]);j;--j)
printf("%d",i);
Heriko Deltana;
}
「2.0」\(n^2\) 过一万
原题目:「B. 排列」
大概是因为数据不满以及上界不严罢,\(O(n^2)\) 真的过了一万……
上次 \(O(n^2)\) 过一万还是在 BCT 的最后一天,那天我上界 \(O(n^2)\),跑得比用记搜的更松上界的 \(O(n^2)\) 跑的还快,全场最优解(
「2.1」题目简述
给定一个序列 \(a\),\(a\) 是一个 \(n\) 的全排列。
定义一个序列为一个 \(m\) 排列,当且仅当存在 \(1 \le l \le r \le m,m=r-l+1\),使得 \(a[l \cdots r]\) 恰好是 \(1\) 到 \(m\) 的一个排列。
提示:显然长度为 \(n\) 的全排列,必然是 \(1\) 排列和 \(n\) 排列。
现在要求输出一个 \(01\) 串,第 \(i\) 位上为 \(1\) 代表 \(a\) 是一个 \(i\) 排列,否则不是。
\(n \le 10000.\)
「2.2」思路简述
考虑这个定义的方式,显然我们在找符合 \(i\) 排列的 \(l,r\) 的时候,可以找到 \(i\) 的位置,再将 \(l,r\) 的位置向左右扩展。而扩展的条件只需要是小于 \(i\) 即可,最后判断一下 \(r-l+1\) 是否 \(=m\) 即可。
「2.3」Code
CI MXX(10001);
bool ans[MXX];
int n,pos[MXX],a[MXX];
S main()
{
Files();
fr(n);
for(int i(1);i<=n;++i) fr(a[i]),pos[a[i]]=i;
for(int i(2);i<n;++i)
{
int l,r;l=r=pos[i];
while(a[l-1]<i and l>1) --l;
while(a[r+1]<i and r<n) ++r;
if((r-l+1)==i) ans[i]=1;
}
ans[1]=1,ans[n]=1;
for(int i(1);i<=n;++i) printf("%d",ans[i]);
Heriko Deltana;
}
「3.0」随机没前途
原题目:「C. 照明」
随机化算法没有前途!!!1
嗯其实是这题随机化太好卡了(
「3.1」题目简述
给定一个 \(n\) 个点 \(m\) 条边的 DAG
,可以将每条边从 R
、G
、B
中选择一种颜色涂色。要求最后的涂色方案不能出现一条长度 \(\ge 42\) 的相同颜色路径,输出其中一种方案即可。
「3.2」思路简述
考场随机拿了 \(30\)(
「3.3」30 pts 做法
最好想到的非正解就是随机化,因为这样看起来碰撞的几率很低。但是这其实是非常好卡掉的,一些特殊构造的拓扑图就能卡掉(使随机的碰撞几率达到很高)。
「3.4」30 pts Code
I int Random() {Heriko ((rand()%3+rand()%3+rand()%10)+rand())%3;}
S main()
{
Files();
srand(407417);
int n,m;fr(n),fr(m);
for(int i(1);i<=m;++i)
{
int co(Random());
if(co==1) puts("G");
else if(co==2) puts("R");
else puts("B");
}
Heriko Deltana;
}
「3.5」正解
正解是构造,每 \(42\) 个分一个小组,\(42\) 个小组分为一个大组,每个大组之间用 B
链接,同大组的小组之间用 G
链接,小组内剩下的 \(41\) 个染 R
.
「3.6」正解 Code
CI NXX(50001),MXX(200001),FT(1764);
int n,m,X[MXX],Y[MXX];
struct node
{
int nex,to;
}
r[MXX];int cnt,head[NXX];
I void Add(CI &x,CI &y) {r[++cnt]=(node){head[x],y};head[x]=cnt;}
int outo[NXX],bfn[NXX];
I void Topo()
{
queue<int> q;
for(int i(1);i<=n;++i)
if(!outo[i])
q.push(i);
int tmp(0);
while(q.size())
{
int x(q.front());q.pop();
bfn[x]=(tmp++);
for(int i(head[x]);i;i=r[i].nex)
if(!(--outo[r[i].to]))
q.push(r[i].to);
}
}
S main()
{
Files();
fr(n),fr(m);
for(int i(1);i<=m;++i)
{
fr(X[i]),fr(Y[i]);
Add(X[i],Y[i]);++outo[Y[i]];
}
Topo();
for(int i(1);i<=m;++i)
{
if((bfn[X[i]]-1)/42 == (bfn[Y[i]]-1)/42) {puts("R");continue;}
else if((bfn[X[i]]-1)/FT == (bfn[Y[i]]-1)/FT) {puts("G");continue;}
puts("B");
}
Heriko Deltana;
}
「4.0」五分差很多
原题目:「D. 相交」
考场挂掉了 95 pts,但是我说实话没想到这个题因为数据水了 \(O(n^4)\) 能到 95 pts.
然鹅正解和我写的差距很大。
「4.1」题目简述
给定 \(n\) 个点(保证没有三个点在同一直线上),求问任意选取四个点两两相连的线段中有多少不相交的。
\(n \le 1000.\)
「4.2」思路简述
考场写的期望 \(30\) 的 \(O(n^4)\),实际应得 \(95\),但是挂掉了ww
「4.3」95 pts 做法
就是简单的枚举四个点然后进行快速排斥实验 + 跨立实验即可。
「4.4」95 pts Code
template<typename J>
I J Hmax(const J &x,const J &y) {Heriko x>y?x:y;}
template<typename J>
I J Hmin(const J &x,const J &y) {Heriko x<y?x:y;}
CI MXX(1001);
const double eps(0.0000000001);
int n;
struct node
{
double x,y;
}
a[MXX];
I bool Checker(node a,node b,node c,node d)
{
if(Hmax(c.x,d.x)<Hmin(a.x,b.x) or Hmax(a.x,b.x)<Hmin(c.x,d.x) or Hmax(c.y,d.y)<Hmin(a.y,b.y) or Hmax(a.y,b.y)<Hmin(c.y,d.y)) Heriko Deltana;
if(eps < ((d.x-a.x)*(d.y-c.y) - (d.y-a.y)*(d.x-c.x)) * ((d.x-b.x)*(d.y-c.y) - (d.y-b.y)*(d.x-c.x))) Heriko Deltana;
if(eps < ((c.x-a.x)*(b.y-a.y) - (c.y-a.y)*(b.x-a.x)) * ((d.x-a.x)*(b.y-a.y) - (d.y-a.y)*(b.x-a.x))) Heriko Deltana;
Heriko Romanno;
}
LL ans;
S main()
{
Files();
ON;
cin>>n;for(int i(1);i<=n;++i) cin>>a[i].x>>a[i].y;
for(int i(1);i<n;++i)
for(int j(i+1);j<=n;++j)
{
bool flg(1);
for(int k(1);k<n;++k)
{
for(int w(k+1);w<=n;++w)
if(i==j or i==k or i==w or j==k or j==w or k==w) continue;
else if(Checker(a[i],a[j],a[k],a[w])) {flg=0;break;}
if(!flg) break;
}
if(flg) ++ans;
}
cout<<ans;
Heriko Deltana;
}
「4.5」正解
正解是二维凸包 + 三角剖分,复杂度 \(O(n^2).\)
「4.6」正解 Code
template<typename J>
I J Hmax(const J &x,const J &y) {Heriko x>y?x:y;}
template<typename J>
I int Sign(const J &x) {Heriko x?(x>0?1:-1):0;}
CI MXX(2001);
struct Triangle
{
int a,b,c;
I bool operator < (const Triangle &co) const {Heriko a==co.a?(b==co.b?c<co.c:b<co.b):a<co.a;}
};
struct Node
{
LL x,y;
I bool operator < (const Node &co) const {Heriko x==co.x?y<co.y:x<co.x;}
I bool operator == (const Node &co) const {Heriko x==co.x and y==co.y;}
}
a[MXX];
I int CCW(const Node &a,const Node &b,const Node &c) {Heriko Sign(a.x*(b.y-c.y)+b.x*(c.y-a.y)+c.x*(a.y-b.y));}
I bool X(const Node &a,const Node &b,const Node &c,const Node &d)
{
if(a==b or a==c or a==d or b==c or b==d or c==d) Heriko Deltana;
else Heriko ((CCW(a,b,c)!=CCW(a,b,d)) and (CCW(a,c,d)!=CCW(b,c,d)));
}
int n;
bool vis[MXX];
vector< pair<int,int> > r;
set<Triangle> t;
I void Into()
{
int lst(0);
do
{
int nex(0);
if(!lst) nex=1;
for(int i(0);i<n;++i)
if(CCW(a[lst],a[nex],a[i])==1)
nex=i;
r.push_back({lst,nex});
if(lst and nex) t.insert({0,nex,lst});
vis[lst]=1;lst=nex;
}
while(lst);
}
I void Divi()
{
for(int i(0);i<n;++i)
{
if(vis[i]) continue;
Triangle x;
for(auto j:t)
if(CCW(a[j.a],a[j.b],a[i])==1 and CCW(a[j.b],a[j.c],a[i])==1 and CCW(a[j.c],a[j.a],a[i])==1)
{x=j;break;}
t.erase(x);t.insert({x.a,x.b,i});t.insert({x.b,x.c,i});t.insert({x.c,x.a,i});
r.push_back({i,x.a});r.push_back({i,x.b});r.push_back({i,x.c});
}
}
int ans,cmpstd;
I bool CMP(int x,int y) {Heriko CCW(a[cmpstd],a[x],a[y])==1;}
I void Work()
{
for(auto co:r)
{
int x(co.first),y(co.second);
vector<int> va,vb;cmpstd=x;
for(int i(0);i<n;++i)
{
int flg(CCW(a[x],a[y],a[i]));
if(flg==-1) va.push_back(i);
else if(flg==1) vb.push_back(i);
}
sort(va.begin(),va.end(),CMP);
sort(vb.begin(),vb.end(),CMP);
vector<int> vc(vb);cmpstd=y;
sort(vc.begin(),vc.end(),CMP);
int pos[n+1];
for(int i(0);i<(int)vc.size();++i) pos[vc[i]]=i;
bool flg(1);int j(0),k(-1);
for(int i(0);i<(int)va.size();++i)
{
while(j<(int)vb.size() and CCW(a[va[i]],a[x],a[vb[j]])==-1) k=Hmax(k,pos[vb[j]]),++j;
if(k!=-1) flg&=(!X(a[x],a[y],a[va[i]],a[vc[k]]));
}
if(flg) ++ans;
}
}
S main()
{
Files();
fr(n);
for(int i(0);i<n;++i) fr(a[i].x),fr(a[i].y);
sort(a,a+n);Into();Divi();Work();fw(ans,1);
Heriko Deltana;
}
「5.0」尾声
写完啦(