# SUSTechCPC-2021Invitation Solution

## Problem A Satori Loves MP3

# include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int a[N];
bool vis[N];
int n;
int main() {
int n; scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) {
for (int j=1;j<=n;j++) vis[j]=false;
int cnt = 0,u = i;
while (!vis[u]) {
cnt++;
vis[u]=1;
u = a[u];
}
printf("%d\n",cnt);
}
return 0;
}


## Problem B Game

# include <bits/stdc++.h>
using namespace std;
const int N=2e4+5;
const int M=65;
int n,m,p,a[N][M],back[M];
int cnt[1<<16];
int main()
{
srand(time(NULL)*10007);
int n,m,p; scanf("%d%d%d",&n,&m,&p);
for (int i=1;i<=n;i++) {
string s; cin>>s;
for (int j=0;j<m;j++)
a[i][j+1]=s[j]-'0';
}
int ans = 0;
for (int time=1;time<=30;time++) {
for (int i=0;i<(1<<15);i++) cnt[i]=0;
int r=1ll*rand()*rand()%n+1,cct = 0;
for (int i=1;i<=m;i++) back[i]=-1;
for (int i=1;i<=m;i++) if (a[r][i]) {
back[i]=cct++;
}
for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++) if (back[j]!=-1&&a[i][j]) {
}
}
for (int i=0;i<15;i++)
for (int j=0;j<(1<<15);j++) if ((j>>i)&1) {
cnt[j^(1<<i)]+=cnt[j];
}
for (int i=0;i<(1<<15);i++) if (cnt[i]>=(1+n)/2) {
int res=0;
for (int j=0;j<15;j++) if ((i>>j)&1) res++;
ans=max(ans,res);
}
}
printf("%d\n",ans);
return 0;
}


## Problem C Path

$1 \leq n,m \leq 2\times 10^5 , 1 \leq w \leq 998244353$

# include <bits/stdc++.h>
# define int long long
# define inf (1e18)
using namespace std;
const int N=2e5+10;
const int mo=998244353;
priority_queue< pair<double,int> >q;
bool v[N];
double d[N];
int tot,n,m;
struct Edge{
double w;
int pre,to,x;
}a[N<<1];
bool vis[N];
{
int X=0,w=0; char c=0;
while (!(c>='0'&&c<='9')) w|=c=='-',c=getchar();
while (c>='0'&&c<='9') X=(X<<1)+(X<<3)+(c^48),c=getchar();
return w?-X:X;
}
void adde(int u,int v,double w,int x) {
a[tot].to=v;
a[tot].w=w;
a[tot].x=x;
}
void dijkstra() {
d[1]=0.0; ans[1]=1;
for (int i=2;i<=n;i++) d[i]=inf;
memset(v,0,sizeof(v));
q.push(make_pair(0.0,1));
while (q.size()) {
int u = q.top().second; q.pop();
if (v[u]) continue;
v[u]=1;
int v=a[i].to; double w = a[i].w; int x=a[i].x;
if (d[v]>d[u]+w) {
d[v]=d[u]+w;
ans[v]=ans[u]*x%mo;
q.push(make_pair(-d[v],v));
}
}
}
}
signed main() {
for (int i=1;i<=m;i++) {
double w = log(x);
}
dijkstra();
for (int i=2;i<=n;i++) printf("%lld\n",ans[i]);
return 0;
}


## Problem D Dating

$b_i=|a_i-i|$是长度为$n$$0-(n-1)$的排列。

• $n \ne 4k \ and \ n \ne 4k+1$ 输出 “No More Dating ”
• $n= 4k \ or \ n =4k+1$ 从正中间开始向右两两交换，最右边的那个自成一个环，其他成为一个大环。

# include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N],ans[N];
int main() {
int n; scanf("%d",&n);
if (n%4==0||n%4==1) {
for (int i=0,l=1,r=n;i<n;i++)
a[i+1]=i&1?r--:l++;
for (int i=(1+n)/2+1;i<=n;i+=2) swap(a[i],a[i+1]);
for (int i=1;i<n-1;i++) ans[a[i]]=a[i+1];
ans[a[n-1]]=a[1],ans[a[n]]=a[n];
for (int i=1;i<=n;i++) printf("%d ",ans[i]);
} else puts("No More Dating");
return 0;
}


## Problem E Sudoku

• 每行是一个$1-9$的排列
• 每列是一个$1-9$的排列
• $9$个的$3\times 3$九宫格内分别是一个$1-9$的排列

# include <bits/stdc++.h>
using namespace std;
int a[10][10];
bool c[10];
bool pd(int xl,int xr,int yl,int yr) {
memset(c,false,sizeof(c));
for (int i=xl;i<=xr;i++)
for (int j=yl;j<=yr;j++) {
if (c[a[i][j]]) return false;
c[a[i][j]]=1;
}
return true;
}
bool check() {
for (int i=1;i<=9;i++)	{
if (!pd(i,i,1,9)) return false;
if (!pd(1,9,i,i)) return false;
}
for (int i=1;i<=9;i+=3)
for (int j=1;j<=9;j+=3) {
if (!pd(i,i+2,j,j+2)) return false;
}
return true;
}
int main()
{
for (int i=1;i<=9;i++)
for (int j=1;j<=9;j++)
scanf("%d",&a[i][j]);
puts(check()?"YES":"NO");
return 0;
}


## Problem F Flipped

• 网络流完全不会，带修改的网络流更加不会了
• skiped
• flipped

## Problem G Meeting

$T (1 \leq T \leq 50000)$组数据，每组数据给出四个坐标$(x_i,y_i) (1 \leq i\leq 4) , 0 \leq |x_i|,|y_i| \leq 10^8$

# include <bits/stdc++.h>
# define int long long
using namespace std;
struct node {
int x,y;
}a[5];
struct rec{
node a,b;
}b[5];
char ch=getchar();int x=0,f=1;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int cx(int x,int y) {
return x-y;
}
int cy(int x,int y) {
return x+y;
}
bool get(int i,int j) {
int x[4],y[4];
x[0]=cx(b[i].a.x,b[i].a.y); y[0]=cy(b[i].a.x,b[i].a.y);
x[1]=cx(b[i].b.x,b[i].b.y); y[1]=cy(b[i].b.x,b[i].b.y);
x[2]=cx(b[j].a.x,b[j].a.y); y[2]=cy(b[j].a.x,b[j].a.y);
x[3]=cx(b[j].b.x,b[j].b.y); y[3]=cy(b[j].b.x,b[j].b.y);
if(max(x[0],x[1])<min(x[2],x[3])||max(x[2],x[3])<min(x[0],x[1])||max(y[0],y[1])<min(y[2],y[3])||max(y[2],y[3])<min(y[0],y[1])) return 0;
else return 1;
}
bool check(int L) {
for (int i=1;i<=4;i++) {
b[i].a.x=b[i].b.x=a[i].x;
b[i].a.y=a[i].y+L; b[i].b.y=a[i].y-L;
}
for (int i=1;i<=4;i++)
for (int j=i+1;j<=4;j++)
if (!get(i,j)) return false;
return true;
}
signed main()
{
while (t--) {
for (int i=1;i<=4;i++) {
}
int l=0,r=1e18,ans;
while (l<=r) {
int mid=(l+r)/2;
if (check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%lld\n",ans);
}
return 0;
}


## Problem H Race

• $l_i\leq l \leq r-1<r \leq r_i$
• $h_l> \max\{ h_{l+1},...,h_{r-1}\}$
• $a_r > \max\{ h_{l},...,h_{r-1}\}$

$i$从左往右扫一下$1-n$,

$h_i$ 插入单调栈，当有元素弹出时，将线段树中的对应元素赋值为$0$，并将删除元素个数$+1$，在树状数组对应位置单点加上线段树上 $l$$i$ 的的所有未删除数的总和。

# include <bits/stdc++.h>
# define int long long
# define lowbit(x) (x&(-x))
using namespace std;
const int N=3e5+10;
int n,q,top,tot;
int a[N],h[N],ans[N];
pair<int,int>s[N];
vector< pair<int,int> >qes[N];
struct Seg {
int l,r;
int res,num,tag;
}tr[N*4];
char ch=getchar();int x=0,f=1;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void build(int x,int l,int r) {
tr[x].l=l; tr[x].r=r;
if (l==r) return;
int mid=(l+r)/2;
build(2*x,l,mid);
build(2*x+1,mid+1,r);
}
void down(int x){
tr[2*x].res+=tr[x].tag*(tr[2*x].r-tr[2*x].l+1-tr[2*x].num);
tr[2*x+1].res+=tr[x].tag*(tr[2*x+1].r-tr[2*x+1].l+1-tr[2*x+1].num);
tr[2*x].tag+=tr[x].tag;
tr[2*x+1].tag+=tr[x].tag;
tr[x].tag=0;
}
void update(int x,int opl,int opr) {
if (opl<=tr[x].l&&tr[x].r<=opr) {
tr[x].tag++;
tr[x].res+=tr[x].r-tr[x].l+1-tr[x].num;
return;
}
down(x);
int mid=(tr[x].l+tr[x].r)/2;
if (opl<=mid) update(2*x,opl,opr);
if (opr>mid) update(2*x+1,opl,opr);
tr[x].res=tr[2*x].res+tr[2*x+1].res;
tr[x].num=tr[2*x].num+tr[2*x+1].num;
}
int query(int x,int opl,int opr) {
if (opl<=tr[x].l&&tr[x].r<=opr) return tr[x].res;
int mid=(tr[x].l+tr[x].r)/2,res=0;
down(x);
if (opl<=mid) res+=query(2*x,opl,opr);
if (opr>mid) res+=query(2*x+1,opl,opr);
return res;
}
void modify(int x,int p) {
if (tr[x].l==tr[x].r) {
tr[x].res=0; tr[x].num=1;
return;
}
down(x);
int mid=(tr[x].l+tr[x].r)/2;
if (p<=mid) modify(2*x,p);
else modify(2*x+1,p);
tr[x].res=tr[2*x].res+tr[2*x+1].res;
tr[x].num=tr[2*x].num+tr[2*x+1].num;
}
int find(int key) {
int l=1,r=top,ans=0;
while (l<=r) {
int mid=(l+r)/2;
if (s[mid].first<key) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
struct BT {
int c[N];
void update(int x,int d) {
for (;x<=n;x+=lowbit(x)) c[x]+=d;
}
int _query(int x) {
int res=0;
for (;x;x-=lowbit(x)) res+=c[x];
return res;
}
int query(int l,int r) {
return _query(r)-_query(l-1);
}
}BT;
signed main() {
build(1,1,n);
for (int i=1;i<=q;i++) {
qes[r].push_back(make_pair(l,i));
}
top=tot=0;
s[++top]=make_pair(h[1],++tot);
for (int r=2;r<=n;r++) {
int t = find(a[r]);
if (t) {
update(1,s[t].second,s[top].second);
}
for (int i=0;i<qes[r].size();i++) {
int l=qes[r][i].first,id=qes[r][i].second;
ans[id]=query(1,l,tot)+BT.query(l,r);
}
while (top&&s[top].first<=h[r]) {
BT.update(s[top].second,query(1,s[top].second,tot));
modify(1,s[top].second);
top--;
}
s[++top]=make_pair(h[r],++tot);
}
for (int i=1;i<=q;i++) printf("%lld\n",ans[i]);
return 0;
}


## Problem I Toilet

$n(1\leq n \leq 10^4)$个人，总共有

$T(1\leq T\leq 10^6)$时间，有$a(1\leq a \leq n)$个男志愿者，$b(1\leq b\leq n)$个女志愿者。

# include <bits/stdc++.h>
using namespace std;
const int N=1e4+10;
const int M=1e6+10;
int T,n,ans[N];
int resv[2];
struct rec{
int op,t,h,id;
}toliet[N];
queue<rec>q[2];
vector<int>backv[M];
bool cmp(rec a,rec b) {
return a.t<b.t;
}
int main()
{
scanf("%d%d%d%d",&n,&T,&resv[1],&resv[0]);
for (int i=1;i<=n;i++) {
string s; int t,h;
cin>>s>>t>>h;
toliet[i]=(rec){s=="M",t,h,i};
}
sort(toliet+1,toliet+1+n,cmp);
for (int i=1;i<=n;i++) {
q[toliet[i].op].push(toliet[i]);
}
for (int time=0;time<T;time++) {
for (int i=0;i<backv[time].size();i++) {
resv[backv[time][i]]++;
}
while (q[0].size()) {
rec u = q[0].front();
if (u.t<=time&&resv[u.op]) {
ans[u.id]=time-u.t;
resv[u.op]--;
if (time+u.h<T) backv[time+u.h].push_back(u.op);
q[0].pop();
} else break;
}
while (q[1].size()) {
rec u = q[1].front();
if (u.t<=time&&resv[u.op]) {
ans[u.id]=time-u.t;
resv[u.op]--;
if (time+u.h<T) backv[time+u.h].push_back(u.op);
q[1].pop();
} else break;
}
}
while (q[0].size()) {
ans[q[0].front().id]=T-q[0].front().t;
q[0].pop();
}
while (q[1].size()) {
ans[q[1].front().id]=T-q[1].front().t;
q[1].pop();
}
for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}


## Problem J Summer Love

$a_i$分成$k$份，最大化每一份最大值减去最小值值之和

• $f[i][j][0][0] = f[i-1][j-1][1][1]$ 新建一个部分，$a_i$不作最大值或者最小值。
• $f[i][j][0][1] = f[i-1][j][1][1] - a[i]$新建一个部分，$a_i$作最小值。
• $f[i][j][1][0] = f[i-1][j][1][1] + a[i]$新建一个部分，$a_i$作最大值。
• $f[i][j][1][1] = f[i-1][j][1][1] +a_i - a_i$新建一个部分，$a_i$作最大值和最小值。

• $f[i][j][0][0] = f[i-1][j][0][0]$ 延续上一个部分，$a_i$不作最大值或者最小值。
• $f[i][j][0][1] = \max \{ f[i-1][j][0][0]-a[i] , f[i][j-1][0][1] \}$ 延续上一个部分，$a_i$可能做最小值。
• $f[i][j][1][0] = \max \{ f[i-1][j][0][0]+a[i] , f[i][j-1][1][0] \}$ 延续上一个部分，$a_i$可能做最大值。
• $f[i][j][1][1] = \max\{f[i-1][j][0][0]+a[i]-a[j],f[i-1][j][0][1]+a[i],f[i-1][j][1][0]-a[i]\},f[i-1][j][1][1]$延续上一个部分，$a_i$可能做最大值，可能做最小值，可能不作最大值或者最小值。

• $f[1][1][0][0]=f[1][1][1][1]=0$
• $f[1][1][0][1]=-a[1]$
• $f[1][1][1][0]=a[1]$
• 其他$-inf$

# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=5e3+10;
int n,k;
int f[2][N][2][2],a[N];
int max2(int x,int y,int z,int t) {
int ans = -1e18;
if (x>ans) ans=x;
if (y>ans) ans=y;
if (z>ans) ans=z;
if (t>ans) ans=t;
return ans;
}
signed main() {
scanf("%lld%lld",&n,&k);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
memset(f,0x8f,sizeof(f));
int p=1;
f[1][1][0][0]=f[1][1][1][1]=0;
f[1][1][0][1]=-a[1];
f[1][1][1][0]=a[1];
for (int i=2;i<=n;i++,p^=1)
for (int j=1;j<=min(i,k);j++) {
f[p^1][j][0][0] = f[p][j-1][1][1];
f[p^1][j][0][1] = f[p][j-1][1][1] - a[i];
f[p^1][j][1][0] = f[p][j-1][1][1] + a[i];
f[p^1][j][1][1] = f[p][j-1][1][1];
f[p^1][j][0][0] = max(f[p][j][0][0],f[p^1][j][0][0]);
f[p^1][j][0][1] = max(max(f[p][j][0][1],f[p][j][0][0]-a[i]),f[p^1][j][0][1]);
f[p^1][j][1][0] = max(max(f[p][j][1][0],f[p][j][0][0]+a[i]),f[p^1][j][1][0]);
f[p^1][j][1][1] = max(max2(f[p][j][1][1],f[p][j][1][0]-a[i],f[p][j][0][1]+a[i],f[p][j][0][0]),f[p^1][j][1][1]);
}
printf("%lld\n",f[p][k][1][1]);
return 0;
}


## Problem K Present

# include<bits/stdc++.h>
using namespace std;
int main()
{
int n; scanf("%d",&n);
printf("0 %d\n",n);
for (int i=1;i<=n;i++) printf("%d ",i);
puts("");
return 0;
}


# include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],p[31],cnt,n;
vector<int>ans;
void insert(int x) {
for (int i=30;i+1;i--) {
if (!(x>>i)) continue;
if (!p[i]) { p[i]=x; cnt++; break;}
x^=p[i];
}
}
void reinsert(int x,int key) {
memset(p,0,sizeof(p));
int rec=x;
for (int i=30;i+1;i--) {
if (!(x>>i)) continue;
if (!p[i]) {
p[i]=x;
if (i<key) ans.push_back(rec);
break;
}
x^=p[i];
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) {
scanf("%d",&a[i]);
insert(a[i]);
}
if (cnt<n) {
printf("0 %d\n",n);
for (int i=1;i<=n;i++) printf("%d ",i);
} else {
int res=(1<<30),id;
for (int i=0;i<=30;i++) if (res>p[i]) {
res=p[i]; id=i;
}
for (int i=1;i<=n;i++) reinsert(a[i],id);
printf("%d %d\n",res,ans.size());
for (int i=0;i<ans.size();i++) printf("%d ",ans[i]);
}
return 0;
}

posted @ 2021-09-24 01:41  Maystern  阅读(19)  评论(0编辑  收藏  举报