CSP-S 模拟赛 34
rnk12,\(24+50+20+0=94\)。
T1 玩游戏
有一个痿正解:从 \(k\) 到 \(1\) 扫左端点,对于每个左端点扫它最远能到达的右端点。如果在任何一时刻它的右端点位置 \(<k\),则断定输出 No
。否则检查当左端点到 \(1\) 时右端点能否到 \(n\)。注意这里扫右端点的方式,不要每次都从 \(k\) 向右扫,而是把右端点定义在外面,然后用和莫队类似的那种方法扫,就极大地降低了复杂度。实测最终 TLE 91pts,很可以了。
考场上连这都想不到?该退役了。
真正的正解貌似更复杂?唐了。
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
template<typename T=int>
T read(){
T x=0,f=1;
char ch=getchar();
while(!isdigit(ch))ch=='-'&&(f=-1),ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
template<typename T>
void write(T x,char sf='\n'){
if(x<0)putchar('-'),x=~x+1;
int top=0;
do str[top++]=x%10,x/=10;while(x);
while(top)putchar(str[--top]+48);
if(sf^'#')putchar(sf);
}
void writes(string s){
for(auto x:s)putchar(x);
putchar('\n');
}
using ll=long long;
constexpr int MAXN=1e5+5;
int T,n,k;
ll a[MAXN],sum[MAXN];
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
T=read();
while(T--){
n=read(),k=read();
memset(sum,0,sizeof(ll)*(n+5));
for(int i=1;i<=n;++i)a[i]=read<ll>();
if(sum[n]-sum[1]>0){
writes("No");
continue;
}
for(int i=k-1;i;--i)sum[i]=sum[i+1]+a[i+1];
for(int i=k+1;i<=n;++i)sum[i]=sum[i-1]+a[i];
int r=k;
for(int i=k;i;--i){
while(sum[r+1]+sum[i]<=0&&r<n)++r;
while(sum[r]+sum[i]>0&&r)--r;
if(r<k){
writes("No");
goto byby;
}
}
writes(r==n?"Yes":"No");
byby:;
}
return fw,0;
}
T2 排列
不用笛卡尔树。设 \(f_{i,j,0/1,0/1}\) 表示长度为 \(i\) 的区间 \(j\) 次合并完,左右两边是否靠墙的前缀和。用前缀和优化 DP。
- 对于 00 的情况(两边都靠墙),可以由 \(j\) 相同的 01 和 10 转移。
- 对于 10 的情况,可以由 \(j-1\) 的 11 和 \(j\) 相同的 10 转移。
- 对于 01 的情况,同理。
- 对于 11 的情况,前缀和神秘转移。
神秘题没什么好说的。
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
#define int long long
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
template<typename T=int>
T read(){
T x=0,f=1;
char ch=getchar();
while(!isdigit(ch))ch=='-'&&(f=-1),ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
template<typename T>
void write(T x,char sf='\n'){
if(x<0)putchar('-'),x=~x+1;
int top=0;
do str[top++]=x%10,x/=10;while(x);
while(top)putchar(str[--top]+48);
if(sf^'#')putchar(sf);
}
constexpr int MAXN=1005;
int n,K,P;
int C[MAXN][MAXN];
int f[MAXN][MAXN][2][2];
void add(int&x,int y){
x=x+y>=P?x+y-P:x+y;
}
int sub(int x,int y){
return x-y<0?x-y+P:x-y;
}
signed main(){
freopen("per.in","r",stdin);
freopen("per.out","w",stdout);
n=read(),K=read(),P=read();
for(int i=0;i<=n;++i){
C[i][0]=1;
for(int j=1;j<=i;++j)C[i][j]=(C[i-1][j]+C[i-1][j-1])%P/*,write(C[i][j])*/;
}
for(int i=0;i<=K;++i)
f[0][i][0][0]=f[0][i][0][1]=f[0][i][1][0]=f[0][i][1][1]=1;
for(int i=1;i<=n;++i)
for(int k=1;k<=K;++k)
for(int j=1;j<=i;++j){
add(f[i][k][0][0],f[j-1][k][0][1]*f[i-j][k][1][0]%P*C[i-1][j-1]%P);
add(f[i][k][0][1],f[j-1][k][0][1]*f[i-j][k-1][1][1]%P*C[i-1][j-1]%P);
add(f[i][k][1][0],f[j-1][k-1][1][1]*f[i-j][k][1][0]%P*C[i-1][j-1]%P);
add(f[i][k][1][1],sub(f[j-1][k][1][1]*f[i-j][k][1][1]%P,sub(f[j-1][k][1][1],f[j-1][k-1][1][1])*sub(f[i-j][k][1][1],f[i-j][k-1][1][1])%P)*C[i-1][j-1]%P);
}
write(sub(f[n][K][0][0],f[n][K-1][0][0]));
return fw,0;
}
T3 最短路
假做法:两遍 Dijkstra。
真假做法:对于每一条边建一条反边,跑二维 Dij。设 \(\mathit{dis}_{i,j}\) 表示沿正边到 \(i\) 点和反边到 \(j\) 的距离之和,则 \(\mathit{dis}_{n,n}\) 即为题中所求。用 bitset 维护原本的 \(\mathit{vis}\) 数组。
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
template<typename T=int>
T read(){
T x=0,f=1;
char ch=getchar();
while(!isdigit(ch))ch=='-'&&(f=-1),ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
template<typename T>
void write(T x,char sf='\n'){
if(x<0)putchar('-'),x=~x+1;
int top=0;
do str[top++]=x%10,x/=10;while(x);
while(top)putchar(str[--top]+48);
if(sf^'#')putchar(sf);
}
constexpr int MAXN=255;
int n,m,p[MAXN];
int hd1[MAXN],tot1,hd2[MAXN],tot2;
struct{int v,nxt;}e1[MAXN*MAXN],e2[MAXN*MAXN];
void addedge(int typ,int u,int v){
if(typ==1){
e1[++tot1]={v,hd1[u]};
hd1[u]=tot1;
}else{
e2[++tot2]={v,hd2[u]};
hd2[u]=tot2;
}
}
struct Node{
int s,x,y;
Node(){}
Node(int s,int x,int y):s(s),x(x),y(y){}
bool operator<(const Node&b)const{
return s>b.s;
}
};
int dis[MAXN][MAXN],vis[MAXN][MAXN];
bitset<MAXN>bit[MAXN][MAXN];
void dijkstra(){
memset(dis,0x3f,sizeof(dis));
dis[1][1]=p[1];
bit[1][1][1]=1;
priority_queue<Node>q;
q.emplace(dis[1][1],1,1);
while(!q.empty()){
int x=q.top().x,y=q.top().y;
q.pop();
if(vis[x][y])continue;
vis[x][y]=1;
for(int i=hd1[x],tmp;i;i=e1[i].nxt){
tmp=0;
if(!bit[x][y][e1[i].v])tmp=p[e1[i].v];
if(dis[e1[i].v][y]>dis[x][y]+tmp){
dis[e1[i].v][y]=dis[x][y]+tmp;
bit[e1[i].v][y]=bit[x][y];
bit[e1[i].v][y][e1[i].v]=1;
q.emplace(dis[e1[i].v][y],e1[i].v,y);
}
}
for(int i=hd2[y],tmp;i;i=e2[i].nxt){
tmp=0;
if(!bit[x][y][e2[i].v])tmp=p[e2[i].v];
if(dis[x][e2[i].v]>dis[x][y]+tmp){
dis[x][e2[i].v]=dis[x][y]+tmp;
bit[x][e2[i].v]=bit[x][y];
bit[x][e2[i].v][e2[i].v]=1;
q.emplace(dis[x][e2[i].v],x,e2[i].v);
}
}
}
}
int main(){
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=n;++i)p[i]=read();
for(int i=1,u,v;i<=m;++i){
u=read(),v=read();
addedge(1,u,v),addedge(2,v,u);
}
dijkstra();
write(dis[n][n]==0x3f3f3f3f?-1:dis[n][n]);
return fw,0;
}
T4 矩形
扫描线 + 并查集。讲得很清楚了。
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;
char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
template<typename T=int>
T read(){
T x=0,f=1;
char ch=getchar();
while(!isdigit(ch))ch=='-'&&(f=-1),ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
template<typename T>
void write(T x,char sf='\n'){
if(x<0)putchar('-'),x=~x+1;
int top=0;
do str[top++]=x%10,x/=10;while(x);
while(top)putchar(str[--top]+48);
if(sf^'#')putchar(sf);
}
constexpr int MAXN=1e5+5;
int n,f[MAXN];
int find(int x){
if(f[x]^x)f[x]=find(f[x]);
return f[x];
}
void combine(int u,int v){
int fu=find(u),fv=find(v);
if(fu^fv)f[fu]=fv;
}
struct JUX{
int x1,y1,x2,y2;
bool operator<(const JUX&b)const{
return y1<b.y1;
}
}a[MAXN];
bool check(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4){
if(x2<x3||x4<x1||y2<y3||y4<y1)return 0;
return 1;
}
namespace zj{
#define lp p<<1
#define rp p<<1|1
#define mid ((s+t)>>1)
struct SegTree{
int id,lim,typ,lazy;
}st[MAXN<<2];
void pushup(int p){
if(st[lp].id==st[rp].id){
st[p].id=st[lp].id;
st[p].lim=st[lp].lim;
st[p].typ=0;
}else st[p].typ=1;
if(st[lp].typ||st[rp].typ)st[p].typ=1;
}
void pushdown(int p){
if(!st[p].lazy)return;
st[lp].lazy=st[rp].lazy=1;
st[lp].id=st[rp].id=st[p].id;
st[lp].lim=st[rp].lim=st[p].lim;
st[p].lazy=0;
}
void mdf(int l,int r,int lim,int id,int s=1,int t=1e5,int p=1){
if(l<=s&&t<=r&&!st[p].typ){
if(st[p].lim>lim)return;
st[p].lazy=1,st[p].id=id,st[p].lim=lim;
return;
}
pushdown(p);
if(l<=mid)mdf(l,r,lim,id,s,mid,lp);
if(mid<r)mdf(l,r,lim,id,mid+1,t,rp);
pushup(p);
}
void Merge(int l,int r,int lim,int id,int s=1,int t=1e5,int p=1){
if(l<=s&&t<=r&&!st[p].typ){
if(st[p].lim>=lim)combine(id,st[p].id);
return;
}
pushdown(p);
if(l<=mid)Merge(l,r,lim,id,s,mid,lp);
if(mid<r)Merge(l,r,lim,id,mid+1,t,rp);
pushup(p);
}
int solve(){
sort(a+1,a+n+1);
for(int i=1;i<=n;++i){
Merge(a[i].x1,a[i].x2,a[i].y1,i);
mdf(a[i].x1,a[i].x2,a[i].y2,i);
}
int ans=0;
for(int i=1;i<=n;++i)if(find(i)==i)++ans;
write(ans);
return fw,0;
}
}
int main(){
freopen("jux.in","r",stdin);
freopen("jux.out","w",stdout);
n=read();
iota(f+1,f+n+1,1);
for(int i=1;i<=n;++i)a[i]={read(),read(),read(),read()};
if(n>=40000)return zj::solve();
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)
if(check(a[i].x1,a[i].y1,a[i].x2,a[i].y2,a[j].x1,a[j].y1,a[j].x2,a[j].y2))
combine(i,j);
int ans=0;
for(int i=1;i<=n;++i)ans+=(find(i)==i);
write(ans);
return fw,0;
}
标签:tmp,ch,int,34,getchar,e1,CSP,模拟,dis
From: https://www.cnblogs.com/laoshan-plus/p/18449918