CF540
CF540A
[CSP-S 2023] 密码锁 easy version
对于每一位 考虑向上还是向下转更优即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define endl '\n'
#define gc cin.get
#define pc cout.put
const int N=1e4+5;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int n,m,ans;
char s[N],t[N];
signed main(){
n=read();
cin>>s+1>>t+1;
for(int i=1;i<=n;i++)
ans+=min((s[i]-t[i]+10)%10,(t[i]-s[i]+10)%10);
cout<<ans<<endl;
return 0;
}
CF540B
首先看给定的数中小于 \(y\) 的数的数量 如果 \(> \dfrac{n}{2}\) 那中位数就被小的数占了 一定无解
剩下情况在前面+1 后面+中位数即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define endl '\n'
#define gc cin.get
#define pc cout.put
const int N=1e5+5;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int n,m,p,k,x,y,ans,a[N];
vector<int>v;
signed main(){
n=read();k=read();p=read();x=read();y=read();
for(int i=1;i<=k;i++)a[i]=read(),x-=a[i];
sort(a+1,a+k+1);
int num=0;
for(int i=1;i<=k;i++)num+=a[i]<y;
if(num>n/2){puts("-1");return 0;}
for(int i=1;i<=min(n/2-num,n-k);i++)v.push_back(1),x--;
int l=v.size();
for(int i=1;i<=n-k-l;i++)v.push_back(y),x-=y;
if(x<0){puts("-1");return 0;}
for(auto i:v)cout<<i<<' ';
return 0;
}
CF540C
大致意思:给定 \(n\times m\) 冰面 碎冰一踩就掉下去 实冰踩一次变成碎冰
要求从终点掉下去
分类讨论:
- 终点是碎冰:踩到终点即可 bfs判断是否可达
- 终点是实冰:需要踩完迂回一下 在终点旁边留一块实冰留着之后踩
然后再不踩这个实冰前提下看看是否能到终点
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define endl '\n'
#define gc cin.get
#define pc cout.put
const int N=1e5+5;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int n,m,a[505][505],b[505][505],sx,sy,tx,ty;
inl bool check(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;}
int dx[5]={0,0,0,-1,1};
int dy[5]={0,-1,1,0,0};
queue<pair<int,int>>q;
inl bool bfs(int x,int y){
q.push({x,y});
while(!q.empty()){
int xx=q.front().first,yy=q.front().second;q.pop();
for(int i=1;i<=4;i++){
int px=xx+dx[i],py=yy+dy[i];
if(!check(px,py))continue;
if(px==tx&&py==ty)return 1;
if(b[px][py])continue;
b[px][py]=1;q.push({px,py});
}
}
return 0;
}
signed main(){
n=read();m=read();
if(n==1&&m==1){puts("NO");return 0;}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char c;cin>>c;
a[i][j]=c=='X';
}
}
sx=read(),sy=read(),tx=read(),ty=read();
if(a[tx][ty]){
memcpy(b,a,sizeof b);
if(bfs(sx,sy))puts("YES");
else puts("NO");
return 0;
}
for(int i=1;i<=4;i++){
int px=tx+dx[i],py=ty+dy[i];
if(!check(px,py))continue;
if(a[px][py])continue;
memcpy(b,a,sizeof b);
b[px][py]=1;
if(bfs(sx,sy)){puts("YES");return 0;}
}
puts("NO");
return 0;
}
CF540D
题意:有三个人,老闭灯、才卓青和james1,老闭灯能吃才卓青,才卓青能吃James1,james1能吃老闭灯。
各有 \(r\) 个老闭灯、 \(s\) 个才卓青和 \(p\) 只James1,每两个人等概率相遇,不同的人必然被吃一个,问最后每个人活下来的概率。
考虑dp。
设 \(f_{i,j,k}\) 表示老闭灯、才卓青和james1分别有 \(i,j,k\) 个的概率
\(f_{r,s,p}=1\)
所有情况即为 \(i\times j+i\times k+j\times k\)
转移:
\(f_{i-1,j,k}=f_{i,j,k}\times i\times k/tot\)
\(f_{i,j-1,k}=f_{i,j,k}\times i\times j/tot\)
\(f_{i,j,k-1}=f_{i,j,k}\times j\times k/tot\)
老闭灯的答案即为 \(\sum\limits_{i=1}^r f_{i,0,0}\)
其他人同理 \(\sum\limits_{i=1}^s f_{0,i,0}\) \(\sum\limits_{i=1}^p f_{0,0,i}\)
CF540E
对于交换后的元素 求逆序对是很简单的:树状数组即可。
考虑没交换的和交换后的元素之间贡献:
不管换前换后,贡献都为位置前后区间中没换的元素个数(手玩一下就可以发现)。
位置前后区间中没换的元素个数 前缀和扫一遍即可。
但蒟蒻手比脑子快 先写了动态开点线段树。。稳居最劣解
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inl inline
#define endl '\n'
#define int ll
#define gc cin.get
#define pc cout.put
const int N=4e5+5;
const int M=1e7+5;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
inl int read(){
int x=0,f=1;char c=gc();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return x*f;
}
inl void write(int x){
if(x<0){pc('-');x=-x;}
if(x>9)write(x/10);
pc(x%10+'0');
}
inl void writei(int x){write(x);pc(' ');}
inl void writel(int x){write(x);pc('\n');}
int n,a[N],b[N],lsh[N],p[N],rt,ans,t,fp[N];
struct segment_tree{
int s[M],ls[M],rs[M],cnt;
#define mid (l+r>>1)
inl void modify(int &k,int l,int r,int x){
if(!k)k=++cnt;s[k]++;
if(l==r)return;
if(x<=mid)modify(ls[k],l,mid,x);
else modify(rs[k],mid+1,r,x);
}
inl int query(int k,int l,int r,int x,int y){
if(!k)return 0;
if(x<=l&&r<=y)return s[k];
int ans=0;
if(x<=mid)ans+=query(ls[k],l,mid,x,y);
if(y>mid)ans+=query(rs[k],mid+1,r,x,y);
return ans;
}
}SGT;
struct binary_index_tree{
int c[N];
inl void add(int x){
for(;x<=t;x+=x&-x)c[x]++;
}
inl int query(int x){
int ans=0;
for(;x;x-=x&-x)ans+=c[x];
return ans;
}
}BIT;
signed main(){
n=read();
for(int i=1;i<=n;i++){
a[i]=lsh[i]=read();
b[i]=lsh[i+n]=read();
}
sort(lsh+1,lsh+(n<<1)+1);
t=unique(lsh+1,lsh+(n<<1)+1)-lsh-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(lsh+1,lsh+t+1,a[i])-lsh;
b[i]=lower_bound(lsh+1,lsh+t+1,b[i])-lsh;
}
for(int i=1;i<=t;i++)p[i]=i;
for(int i=1;i<=n;i++)swap(p[a[i]],p[b[i]]);
for(int i=1;i<=t;i++){
ans+=i-1-BIT.query(p[i]);
BIT.add(p[i]);
}
for(int i=1;i<=t;i++)fp[p[i]]=i;
for(int i=1;i<=t;i++)
SGT.modify(rt,1,1e9,lsh[i]);
for(int i=1;i<=t;i++){
if(lsh[fp[i]]>lsh[i])ans+=lsh[fp[i]]-lsh[i]+1-SGT.query(rt,1,1e9,lsh[i],lsh[fp[i]]);
else ans+=lsh[i]-lsh[fp[i]]+1-SGT.query(rt,1,1e9,lsh[fp[i]],lsh[i]);
}
cout<<ans<<endl;
return 0;
}