CSP 后多校七
A. 谜之阶乘
签到题.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define int long long
#define lf long double
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->int{
int w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
const int inf=1e18;
int m,n,cnt;
int ans[10][2];
auto calc=[](int x,int len,int res=1)->int{
for(int i=1;i<=len;i++){
if(res>(inf)/(i+x)) return -1;
res=res*(i+x);
}
return res;
};
auto solve=[](int x,int len)->int{
int l=1,r=pow(x,1.0/(1.0*len))+1,w,mid,res=-1;
while(l<=r){
mid=(l+r)>>1,w=calc(mid,len);
if(w>=x or w<0) r=mid-1,res=mid;
else l=mid+1;
}
return (calc(res,len)==x) ? res : -1 ;
};
auto Work=[]()->void{
n=read(),cnt=0; int res;
if(n==1) { puts("-1"); return ; }
if(n==2) { puts("1"),puts("2 1"); return; }
for(int i=20;i>=2;i--){
res=solve(n,i);
if(~res) ans[++cnt][0]=res+i,ans[cnt][1]=res;
}
printf("%lld\n",cnt+1);
for(int i=1;i<=cnt;i++) printf("%lld %lld\n",ans[i][0],ans[i][1]);
printf("%lld %lld\n",n,n-1);
};
signed main(){
File(factorial);
for(int Ts=read();Ts;Ts--) Work();
exit(0);
}
B. 子集
签到题.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define int long long
#define lf long double
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->int{
int w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
const int N=1e6+21;
int n,m,sum;
vector<int> vec[N];
auto SpWork1=[]()->void{
int x=n/m-2,j=1;
for(int i=1;i<=x;i++){
if(i&1) for(int k=1;k<=m;k++) vec[k].pb(j++);
else for(int k=m;k;k--) vec[k].pb(j++);
}
for(int i=m/2+1;i<=m;i++) vec[i].pb(j++);
for(int i=1,lmi=m/2;i<=lmi;i++) vec[i].pb(j++);
for(int i=m/2+1,k=n;i<=m;i++,k-=2) vec[i].pb(k);
for(int i=1,k=n-1,lmi=m/2;i<=lmi;i++) vec[i].pb(k),k-=2;
};
auto SpWork2=[]()->void{
for(int i=1,j=1;i<=n/m;i++){
if(i&1) for(int k=1;k<=m;k++) vec[k].pb(j++);
else for(int k=m;k;k--) vec[k].pb(j++);
}
};
auto Work=[]()->void{
n=read(),m=read(),sum=n*(n-1)>>1ll;
if(m==1 and n==1) { puts("Yes\n1"); return ;}
if(sum%m or n==m) { puts("No"); return ; }
// assert(((n&1)==0 and ((n/m)&1))==0);
((n/m)&1) ? SpWork1() : SpWork2();
puts("Yes");
for(int i=1;i<=m;i++){
for(auto j : vec[i]) printf("%lld ",j);
puts("");
}
for(int i=1;i<=m;i++) vec[i].clear();
};
signed main(){
File(subset);
for(int Ts=read();Ts;Ts--) Work();
exit(0);
}
C. 混凝土粉末
分块没打出来,自己还是没掌握得更好.
正解树状数组二分 \(+\) 扫描线.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define int long long
#define lf long double
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->int{
int w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
#define fi first
#define se second
const int N=1e6+21;
int m,n,ops;
int ans[N];
struct I { int opt,x,y,h; } p[N];
vector<pair<int,int> > inc[N],dic[N],qry[N];
struct FenWick{
int res=0; int c[N];
inline void update(int x,int w){
for(;x<=ops;x+=lbt(x)) c[x]+=w;
}
inline int query(int lmx,int y,int x=0){
for(int i=20;~i;i--){
if((x|1<<i)<=lmx and c[x|1<<i]<y) x|=1<<i,y-=c[x];
}
return x==lmx ? 0 : x+1 ;
}
}bit;
signed main(){
File(concrete);
n=read(),ops=read();
for(int i=1;i<=ops;i++){
if((p[i].opt=read())&1){
p[i].x=read(),p[i].y=read(),p[i].h=read();
inc[p[i].x].pb(mp(p[i].h,i)),dic[p[i].y].pb(mp(p[i].h,i));
}
else{
p[i].x=read(),p[i].y=read();
qry[p[i].x].pb(mp(p[i].y,i));
}
}
for(int i=1;i<=n;i++){
for(auto j : inc[i]) bit.update(j.se,j.fi);
for(auto j : qry[i]) ans[j.se]=bit.query(j.se,j.fi);
for(auto j : dic[i]) bit.update(j.se,-j.fi);
}
for(int i=1;i<=ops;i++) if(p[i].opt&2) printf("%lld\n",ans[i]);
exit(0);
}
D. 排水系统
\(DAG\) 上跑 \(dp\),一看是期望,果断选择线性拆开求和.
然后考虑每条边删去后的贡献,暴力的思想就是删掉之后分别统计.
考虑不再枚举重复状态,也就是充分利用已有状态,不难想到要在最原始的图上做一些措施.
首先思考如果每条边的 \(a\) 都是 \(0\),那么很容易就做出来;
如果只有一条边的 \(a\) 不是 \(0\),那么不难想到就是要删掉之后分给其它点,也很容易;
现在考虑如果有两条边的 \(a\) 不是 \(0\),那么考虑在做第二条边的时候怎么做才能使用到做第一条边的图.
发现如果根据提题意硬做,那么很难利用做之前的边的时候出现的图,所以可以考虑转化,将贡献转移.
观察到一条边 \(\{u,v\}\) 删掉对于 \(u\) 的点权没有影响,但是对 \(v\) 和 \(v\) 的兄弟有影响,所以可以选择把边删掉的影响转移到 \(u\) 和 \(v\) 上.
于是跑两次 \(dp\) 就完了.
D_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS{
#define int long long
#define lf long double
#define pb push_back
#define mp make_pair
#define lb lower_bound
#define ub upper_bound
#define lbt(x) ((x)&(-(x)))
#define Fill(x,y) memset(x,y,sizeof(x))
#define Copy(x,y) memcpy(x,y,sizeof(x))
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
auto read=[]()->int{
int w=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) w=(w<<3)+(w<<1)+(ch^48),ch=getchar();
return cit?w:(-w);
};
} using namespace BSS;
const int mod=998244353,N=2e5+21,M=5e5+21;
int m,n,s,t,ts,sum,inv;
int d[N],cu[N],ru[N],ot[N],pt[N],val[N],inc[N],head[N];
struct I { int u,v,w,nxt; } e[M];
queue<int> que;
auto add=[](int u,int v,int w)->void{
e[++ts].u=u,e[ts].v=v,e[ts].w=w;
e[ts].nxt=head[u],head[u]=ts;
};
auto ksm=[](int a,int b,int c,int w=1)->int{
for(a%=c;b;b>>=1,a=a*a%c) if(b&1) w=w*a%c;
return w%c;
};
auto bfs=[]()->void{
assert(que.empty());
for(int i=1;i<=n;i++){
val[i]=inc[i]+pt[i],d[i]=ru[i];
if(pt[i]) que.push(i);
}
int u,v;
while(que.size()){
u=que.front(),que.pop();
for(int i=head[u];i;i=e[i].nxt){
(val[v=e[i].v]+=val[u]*ksm(cu[u],mod-2,mod)%mod)%=mod;
if(!(--d[v])) que.push(v);
}
}
};
signed main(){
File(water);
n=read(),s=read(),t=read(),m=read(); int u,v,w;
for(int i=1;i<=m;i++){
u=read(),v=read(),w=read(),sum+=w;
cu[u]++,ru[v]++,add(u,v,w);
}
for(int i=1;i<=n;i++) ot[i]=(!cu[i]),pt[i]=(!ru[i]);
inv=ksm(sum,mod-2,mod); bfs();
for(int i=1;i<=m;i++){
u=e[i].u,v=e[i].v,w=e[i].w*inv%mod*val[u]%mod*ksm(cu[u]-1,mod-2,mod)%mod;
inc[u]=(inc[u]+w)%mod,inc[v]=(inc[v]-w+mod)%mod;
}
bfs();
for(int i=1;i<=n;i++) if(ot[i]) printf("%lld ",val[i]);
exit(0);
}