CSP 后多校十七
A. ladice
不难发现一个联通块内只要点数大于边数就可以.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define int long long
#define lf long double
#define pb push_back
#define kap make_pair
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(y))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?(-w):w;
};
} using namespace BSS;
#define merge asasasasas
#define Yes() puts("LADICA")
#define No() puts("SMECE")
const int N=3e5+21;
int m,n,flag;
int con[N],siz[N],fa[N];
int id[N][2];
int fond(int x){ return x==fa[x] ? x : fa[x]=fond(fa[x]); }
auto merge=[](int x,int y)->int{
x=fond(x),y=fond(y);
if(x==y) return x;
if(siz[x]>siz[y]) swap(x,y);
fa[x]=y,siz[y]+=siz[x],con[y]+=con[x];
return y;
};
signed main(){
File(ladice);
n=read(),m=read(); int x,y,z;
for(int i=1;i<=m;i++) siz[i]=1,fa[i]=i;
for(int i=1;i<=n;i++){
id[i][0]=read(),id[i][1]=read();
x=merge(id[i][0],id[i][1]);
if(siz[x]>con[x]) con[x]++,Yes();
else No();
}
exit(0);
}
B. card
考虑需要什么,然后直接设状态,做题怂了不应该.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define int long long
#define lf long double
#define pb push_back
#define kap make_pair
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(y))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?(-w):w;
};
} using namespace BSS;
const int N=505;
int m,n,ans;
int pre[N];
struct I { int a,b,w; } p[N];
bool dp[N][N][N][2];
auto calc=[](int i,int j,int k,int opt)->int{
int res=pre[i-1]+pre[j-1]-pre[i]+pre[k-1]-pre[j];
// if((res+(opt ? p[k].w : p[i].w))==20) cout<<i<<' '<<j<<' '<<k<<' '<<opt<<endl;
return res+=(opt ? p[k].w : p[i].w);
};
signed main(){
File(card);
n=read(),dp[1][2][3][0]=1,dp[1][2][3][1]=1;
for(int i=1;i<=n;i++) p[i].a=read(),p[i].b=read(),p[i].w=read();
for(int i=1;i<=n+1;i++) pre[i]=pre[i-1]+p[i].w;
if(n==1) printf("%lld\n",p[1].w),exit(0);
if(n==2){
if(p[1].a==p[2].a or p[1].b==p[2].b) printf("%lld\n",pre[2]),exit(0);
else printf("%lld\n",max(p[1].w,p[2].w)),exit(0);
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
for(int k=j+1;k<=n;k++){
if(dp[i][j][k][0]){
if(p[i].a==p[k+1].a or p[i].b==p[k+1].b){
dp[j][k][k+1][1]=1;//,ans=max(ans,calc(j,k,k+1,1));
}
if(p[i].a==p[j].a or p[i].b==p[j].b){
dp[j][k][k+1][0]=1;//,ans=max(ans,calc(j,k,k+1,0));
}
ans=max(ans,calc(i,j,k,0));
}
if(dp[i][j][k][1]){
if(p[i].a==p[k].a or p[i].b==p[k].b){
dp[i][j][k+1][0]=1;//,ans=max(ans,calc(i,k,k+1,0));
}
if(p[k].a==p[k+1].a or p[k].b==p[k+1].b){
dp[i][j][k+1][1]=1;//,ans=max(ans,calc(i,j,k+1,1));
}
ans=max(ans,calc(i,j,k,1));
}
}
if(dp[i][j][n+1][0]) ans=max(ans,calc(i,j,n+1,0)+p[j].w*(p[i].a==p[j].a or p[i].b==p[j].b));
}
}
printf("%lld\n",ans),exit(0);
}
C. dojave
手玩找规律推性质,然后想办法维护一下相同的次数,直接 \(Hash\) 就很方便.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define int long long
#define lf long double
#define pb push_back
#define kap make_pair
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(y))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?(-w):w;
};
} using namespace BSS;
#define pii pair<int,int>
const int N=(1<<20)+21,M=21;
int m,n,ans;
int pos[N],val[N];
int pre[N][2];
map<pii,int> mp[5];
signed main(){
File(dojave);
srand(time(0)*clock());
m=n=read(),n=1<<n; int U=n-1;
if(m==1) puts("2"),exit(0);
for(int i=1;i<=n;i++) pos[val[i]=read()]=i;
for(int i=1;i<=n;i++){
pre[i][0]=pre[pos[U^val[i]]][0]=rand()|(rand()<<15);
pre[i][1]=pre[pos[U^val[i]]][1]=rand()|(rand()<<15);
}
for(int i=1;i<=n;i++) pre[i][0]^=pre[i-1][0],pre[i][1]^=pre[i-1][1];
mp[0][kap(0,0)]=1;
for(int i=1;i<=n;i++){
int z=i%4;
pii x=kap(pre[i][0],pre[i][1]);
ans+=mp[z][x],mp[z][x]++;
}
printf("%lld\n",n*(n+1)/2-ans),exit(0);
}
D. drop
有一个性质,一个柱子上面的水的体积就是左侧最大值和右侧最大值中更小的一个的高度减去自己的高度.
所以排序后再做会很方便.
设 \(f_i\) 表示在填完第 \(i\) 个柱子后所能拥有的水的体积,\(bitset\) 写起来比较方便.
转移:\(f_i=\bigcup\limits_{j=2}^{j<i} f_{i-1}<<(h_j-h_i)\).
D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
// #define int long long
#define lf long double
#define pb push_back
#define kap make_pair
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(y))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[](int w=0,bool cit=0,char ch=getchar())->int{
while(!isdigit(ch)) cit|=(ch=='-'),ch=getchar();
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?(-w):w;
};
} using namespace BSS;
const int M=40005,N=505;
int m,n;
int val[M];
bitset<M> f[N];
signed main(){
File(drop);
n=read(),f[1][0]=1;
for(int i=1;i<=n;i++) val[i]=read();
sort(val+1,val+1+n,[](int i,int j){ return i>j; });
for(int i=2;i<=n;i++){
f[i]=f[i-1];
for(int j=2;j<i;j++) f[i]|=(f[i-1]<<(val[j]-val[i]));
}
for(int i=0;i<M;i++) if(f[n][i]) printf("%d ",i);
exit(0);
}
上善若水,水善利万物而不争.