ABC 326
AK 了就随便写写,等 cf。
A
按照题意模拟即可。
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
using namespace std;
const int N=2e5+60,M=2e6+20,mod=998244353;
int n,a,b;
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>a>>b;
if(a>=b){
if(a-b<=3) return cout<<"Yes\n",0;
else return cout<<"No\n",0;
}
else{
if(b-a<=2) return cout<<"Yes\n",0;
else return cout<<"No\n",0;
}
return 0;
}
B
暴力扫答案,暴力判断即可。
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
using namespace std;
const int N=2e5+60,M=2e6+20,mod=998244353;
int n;
inline bool chk(int x){
int a=x%10,b=(x/10)%10,c=x/100;
return b*c==a;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=n;;i++) if(chk(i)) return cout<<i<<'\n',0;
return 0;
}
C
维护双指针,暴力扫右指针,维护最远可以加入的左边元素即可。
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
using namespace std;
const int N=3e5+60,M=2e6+20,mod=998244353;
int n,m,a[N];
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
int ans=0;
for(int i=1,j=1;i<=n;i++){
while(a[i]-a[j]>=m) j++;
ans=max(ans,i-j+1);
}
cout<<ans<<'\n';
return 0;
}
D
爆搜加剪枝,首先观察到一个显然的剪枝是每次扫到一个状态都判一下合法性,逐行放置,行的合法性在放的时候就可以满足,能减少不少无用转移,最后扫到的状态在判一下列的 \(A,B,C\) 均只出现一次即可。
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
using namespace std;
const int N=60,M=2e6+20,mod=998244353;
int n;
char a[N][N];
char R[N],C[N];
bool chk(int x){
for(int j=1;j<=n;j++){
for(int i=1;i<x;i++) if(a[i][j]!='.'){
if(a[i][j]!=C[j]) return 0;else break;
}
}return 1;
}
int t[3];
bool Chk(){
for(int j=1;j<=n;j++){
t[0]=t[1]=t[2]=0;
for(int i=1;i<=n;i++){
if(a[i][j]!='.') t[a[i][j]-'A']++;
}
// cout<<t[0]<<t[1]<<t[2]<<'\n';
if(t[0]!=1||t[1]!=1||t[2]!=1) return 0;
}
return 1;
}
void dfs(int x){
if(!chk(x)) return ;
if(x>n){
// cout<<"--------\n";
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
// cout<<a[i][j];
// }cout<<'\n';
// }
if(!Chk()) return ;
cout<<"Yes\n";
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<a[i][j];
}cout<<'\n';
}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++){
a[x][i]=R[x];
if(R[x]=='A'){
a[x][j]='B';
a[x][k]='C';
dfs(x+1);
a[x][j]='C';
a[x][k]='B';
dfs(x+1);
}
if(R[x]=='B'){
a[x][j]='A';
a[x][k]='C';
dfs(x+1);
a[x][j]='C';
a[x][k]='A';
dfs(x+1);
}
if(R[x]=='C'){
a[x][j]='A';
a[x][k]='B';
dfs(x+1);
a[x][j]='B';
a[x][k]='A';
dfs(x+1);
}
a[x][i]=a[x][j]=a[x][k]='.';
}
}
}
}
signed main(){
// ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
scanf("%s%s",R+1,C+1);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]='.';
dfs(1);
cout<<"No\n";
return 0;
}
E
期望 dp,设 \(f_i\) 表示当前初始 \(x=i\) 的期望工资,转移 \(f_{i}=\sum\limits_{j>i} \dfrac{A_j+f_j}{n}\),后缀和优化转移即可做到 \(O(n)\)。
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
using namespace std;
const int N=3e5+60,M=2e6+20,mod=998244353;
int n,f[N],a[N],s[N];
int qpow(int a,int b){
int res=1;
while(b){
if(b&1) res=1ll*res*a%mod;
a=1ll*a*a%mod;b>>=1;
}return res;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int invn=qpow(n,mod-2);
for(int i=1;i<=n;i++) s[i]=(s[i-1]+1ll*a[i]*invn%mod)%mod;
f[n]=0;int sum=0;
for(int i=n-1;i>=0;i--){
f[i]=(1ll*s[n]-s[i]+sum+mod)%mod;
sum=(sum+1ll*f[i]*invn%mod)%mod;
}
cout<<f[0]<<'\n';
return 0;
}
F
首先不难发现的是,奇数操作必然往上下,偶数位置必然往左右,而其往上下还是左右都可以任意选择,变化一下贡献形式,每次相当于背包,折半搜索即可,复杂度 \(O(2^{n/4} \log n)\)。
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
//#define int ll
using namespace std;
const int N=2e5+60,M=2e6+20,mod=998244353;
int x,y,n,a[N];
int b[N],totb,c[N],totc;
map<int,int> mpb,mpc;
ll Sb,Sc;
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>x>>y;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
if(~i&1) b[++totb]=a[i],x+=a[i];
else c[++totc]=a[i],y+=a[i];
}
if(x&1) return cout<<"No",0;
if(y&1) return cout<<"No",0;
x/=2,y/=2;
int limb=min(20,totb);
for(int i=0;i<(1<<limb);i++){
int res=0;
for(int j=0;j<limb;j++) if(i>>j&1){
res+=b[j+1];
}
mpb[res]=i+1;
// cout<<res<<'\n';
}
int limc=min(20,totc);
for(int i=0;i<(1<<limc);i++){
int res=0;
for(int j=0;j<limc;j++) if(i>>j&1){
res+=c[j+1];
}
mpc[res]=i+1;
}
int res=0;bool fl=0;
for(int i=0;i<1<<(totb-limb);i++){
int res=0;
for(int j=0;j<(totb-limb);j++) if(i>>j&1){
res+=b[j+limb+1];
}
if(mpb[x-res]){
Sb=(mpb[x-res]-1)|((ll)i<<limb);
fl=1;
break;
}
}
if(!fl) return cout<<"No\n",0;
fl=0;
for(int i=0;i<1<<(totc-limc);i++){
int res=0;
for(int j=0;j<(totc-limc);j++) if(i>>j&1){
res+=c[j+limc+1];
}
if(mpc[y-res]){
Sc=(mpc[y-res]-1)|((ll)i<<limc);
fl=1;
break;
}
}
if(!fl) return cout<<"No\n",0;
cout<<"Yes\n";
// cout<<Sc<<'\n';
int p=1;
for(int i=1;i<=n;i+=2){
int j=(i-1)>>1;
if(Sc>>j&1){
if(p) cout<<'L',p=1;
else cout<<'R',p=1;
}else{
if(p) cout<<'R',p=0;
else cout<<'L',p=0;
}
if(i+1<=n){
if((Sb>>j&1)){
if(p) cout<<'R',p=1;
else cout<<'L',p=1;
}else{
if(p) cout<<'L',p=0;
else cout<<'R',p=0;
}
}
}
return 0;
}
G
经典网络流题,建模如下:
\(S\xrightarrow{a_i} i\)
\(i\xrightarrow{+\infty} (j,k) ,k<L_{i,j}\)
\((j,k)\xrightarrow{c_j} T\)
考虑这么建模的意义,若在右部点删点,表示选择了右部点升级,贡献 \(-c_i\),没删左部点,表示左部点奖励拿到,贡献 \(a_i\),求最小割。
所以 \(\sum a_i-\text{maxflow}\) 即为所求。
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
#define int ll
#define pb push_back
using namespace std;
const int N=1e6+20,M=2e6+20,Inf=0x3f3f3f3f3f3f3f3fll;
namespace mf{//remember ecnt=1 init
struct Edge{int v,c,f;}g[M];
int n,s,t,cur[N],d[N],ecnt=1;
vector<int> e[N];
inline void add(int u,int v,int c){g[++ecnt]=(Edge){v,c,0};e[u].pb(ecnt);}
inline void add_edge(int u,int v,int c){add(u,v,c);add(v,u,0);}
bool bfs(){
queue<int> q;
for(int i=0;i<=n;i++) d[i]=Inf;
d[s]=0;q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int i:e[u]){
Edge x=g[i];
if(d[x.v]==Inf&&g[i].c>g[i].f){
d[x.v]=d[u]+1;
q.push(x.v);
}
}
}return d[t]!=Inf;
}
int dfs(int u,int a){
if(!a||u==t) return a;
int f,flow=0;
for(int &i=cur[u];i<(int)e[u].size();i++){
Edge x=g[e[u][i]];
if(x.c>x.f&&d[x.v]==d[u]+1&&(f=dfs(x.v,min(a,x.c-x.f)))){
flow+=f;a-=f;g[e[u][i]].f+=f;g[e[u][i]^1].f-=f;
if(!a) return flow;
}
}return flow;
}
int solve(){
int res=0;
while(bfs()){
for(int i=0;i<=n;i++) cur[i]=0;
res+=dfs(s,Inf);
}return res;
}
}
int n,m,c[N],a[N],L[60][60];
int sum,id[N][10],cnt,Id[N];
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>m;mf::s=0;
for(int i=1;i<=n;i++) for(int j=1;j<=4;j++) id[i][j]=++cnt;
for(int i=1;i<=m;i++) Id[i]=++cnt;
mf::n=++cnt;mf::t=cnt;
for(int i=1;i<=n;i++) cin>>c[i];
for(int i=1;i<=m;i++) cin>>a[i];
for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) cin>>L[i][j];
for(int i=1;i<=m;i++) mf::add_edge(mf::s,Id[i],a[i]),sum+=a[i];
for(int i=1;i<=n;i++) for(int j=1;j<=4;j++)
mf::add_edge(id[i][j],mf::t,c[i]);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=L[i][j]-1;k++){
mf::add_edge(Id[i],id[j][k],Inf);
}
}
}
cout<<sum-mf::solve()<<'\n';
return 0;
}```