传送门
总述
比赛中过了4/6,rank26。
罚时感觉还是蛮多的(跟我一个oier有什么关系)。
最后一个题贪心贪错了,貌似如果是oi赛制会有60分。
A.牛牛吃米粒
考虑按二进制位拆分。
只要有一位不能满足要求,则输出NO。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
unsigned long long s;
int n,k,v[70],a[70],cnt;
int main(){
ios::sync_with_stdio(false);
cin>>n>>k>>s;
for(int i=1;i<=k;i++) cin>>a[i],v[a[i]]=1;
while(s>0){
cnt++;
if(s&1){
if(v[cnt]==1){
cout<<"NO"<<endl;
return 0;
}
}
s/=2;
}
cout<<"YES"<<endl;
return 0;
}
B.牛牛嚯可乐
固定的字符串,长度为8。
直接暴力dfs即可。
代码放std吧。
#include<bits/stdc++.h>
using namespace std;
int ans = 10;
char a[10];
char b[] = "cocacola";
inline void dfs(int pos, int move)
{
if(pos == 8)
return (void)(ans = min(ans, move));
if(a[pos] == b[pos])
dfs(pos + 1, move);
else
{
for (int i = pos + 1; i <= 7; i++)
if(a[i] == b[pos])
{
swap(a[i], a[pos]);
dfs(pos + 1, move + 1);
swap(a[i], a[pos]);
}
}
}
int main()
{
scanf("%s", a);
dfs(0, 0);
cout << ans << endl;
return 0;
}
C.牛牛吃豆人
要求吃2*个豆子,也就是说两个人必须都能走到终点且路径不想交。
因为列数为3,所以方法很多。
首先可以直接dfs模拟一遍(第一个人尽量向下走并将走过的点设为障碍,判断第二个人能否到达)。
或者手推一下发现对障碍的要求是第二列障碍必须严格在第三列最下面的障碍下面、第一列的最上面的障碍上面(保证之间能通过人)。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
int n,m,ma[maxn][5];
bool dfs(int x,int y){
cout<<x<<" "<<y<<endl;
if(x>n||y>3) return 0;
if(x==n&&y==2) return 1;
if(x==n-1&&y==3) return 1;
if(ma[x+1][y]==0){
ma[x+1][y]=1;
if(dfs(x+1,y)) return 1;
}
if(ma[x][y+1]==0){
ma[x][y+1]=1;
if(dfs(x,y+1)) return 1;
}
return 0;
}
bool work(int x,int y){
while(1){
ma[x][y]=1;
if(x==n&&y==2) return 1;
if(x==n-1&&y==3) return 1;
if(x<n&&(ma[x+1][y]==0)){
x++;
continue;
}
if(y<3&&ma[x][y+1]==0){
y++;
continue;
}
return 0;
}
}
template<class T>inline void read(T &x)
{
x=0; char c=getchar(); bool f=0;
while(!isdigit(c))f^=c=='-',c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(f)x=-x;
}
int main(){
read(n);
read(m);
for(int i=1;i<=m;i++){
int x,y;
read(x);
read(y);
ma[y][x]=1;
}
if(!dfs(2,1)){
cout<<"NO";
return 0;
}
if(!dfs(1,2)){
cout<<"NO";
return 0;
}
// if(!work(1,1)){
// cout<<"NO";
// return 0;
// }
// if(!work(1,1)){
// cout<<"NO";
// return 0;
// }
cout<<"YES";
return 0;
}
D.牛牛种小树
乍一看像图论题,实际上是个dp。
给你n个节点的树,实际上对度数的要求只有和为(2n-2)。
也就是说,求:
[max(f(a_1)+f(a_2)+cdots+f(a_n)) quad a_1+a_2+a_3+cdots+a_n=2n-2quad a_i>=1
]
这样并不好求。
所以可以把这n个数先提出n个f(1)来,这样最后答案就变成了:
[max(f(b_1)+f(b_2)+cdots+f(b_k)) quad b_1+b_2+b_3+cdots+b_k=n-2 quad b_i,k>0
]
这就成了一个完全背包的形式。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=2e4+5;
int n;
long long a[maxn],ans,dp[maxn];
int main(){
ios::sync_with_stdio(false);
memset(dp,-0x3f,sizeof(dp));
dp[0]=0;
cin>>n;
for(int i=1;i<n;i++) cin>>a[i];
ans=a[1]*n;
for(int i=2;i<n;i++) a[i]-=a[1];
for(int i=1;i<n;i++){
for(int j=i;j<=n-2;j++){
dp[j]=max(dp[j],dp[j-i]+a[i+1]);
}
}
cout<<ans+dp[n-2];
return 0;
}
E.牛牛小数点
不会,放题解:
https://blog.nowcoder.net/n/45758a7ca92c4f66959e832ade4b3734
F.牛牛防疫情
比赛的时候想了个假贪心,挂到60pts。
正解是网络流。
其实也挺显然的。
从超级源点向感染源建立一条流量为INF的边,从安全区向汇点建立一条流量为c的边,从每个点向周围建立一条流量为1的边。
最后就是求最小割(代表着最少用多少流量控制住了疫情)。
当然也就等于求最大流。
直接扔标程。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=910;
const int maxm=1e4+10;
int level[maxn],n,m,c,x,y;
int head[maxn],cnt;
bool is[maxn];
bool in(int x,int y){
return x>=0 && x<n && y>=0 && y<n;
}
int f(int x,int y){
return x*n+y;
}
struct edge{int v,nex;ll w;}e[maxm];
void init(){
cnt=0;
memset(head,-1,sizeof head);
}
void add(int u,int v,ll w){
e[cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt++;
}
void add2(int u,int v,ll w,bool op){
add(u,v,w);
add(v,u,op?0:w);
}
bool bfs(int s,int t){
queue<int>q;
memset(level,0,sizeof level);
level[s]=1;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
if(x==t)return 1;
for(int u=head[x];~u;u=e[u].nex){
int v=e[u].v;ll w=e[u].w;
if(!level[v]&&w){
level[v]=level[x]+1;
q.push(v);
}
}
}
return 0;
}
ll dfs(int u,ll maxf,int t){
if(u==t)return maxf;
ll ret=0;
for(int i=head[u];~i;i=e[i].nex){
int v=e[i].v;ll w=e[i].w;
if(level[u]+1==level[v]&&w){
ll MIN=min(maxf-ret,w);
w=dfs(v,MIN,t);
e[i].w-=w;
e[i^1].w+=w;
ret+=w;
if(ret==maxf)break;
}
}
if(!ret)level[u]=-1;
return ret;
}
ll Dinic(int s,int t){
ll ans=0;
while(bfs(s,t))
ans+=dfs(s,INF,t);
return ans;
}
int main(){
init();
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=m;++i){
scanf("%d%d",&x,&y);
is[f(x,y)]=1;
}
int S=n*n+1,T=S+1;
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
if(is[f(i,j)]){
add2(S,f(i,j),INF,0);
if(i+1<n){
if(is[f(i+1,j)]){
add2(f(i,j),f(i+1,j),INF,0);
}
else{
add2(f(i,j),f(i+1,j),1,0);
}
}
if(j+1<n){
if(is[f(i,j+1)]){
add2(f(i,j),f(i,j+1),INF,0);
}
else{
add2(f(i,j),f(i,j+1),1,0);
}
}
}
else{
add2(f(i,j),T,c,0);
if(i+1<n){
add2(f(i,j),f(i+1,j),1,0);
}
if(j+1<n){
add2(f(i,j),f(i,j+1),1,0);
}
}
}
}
printf("%d
",Dinic(S,T));
return 0;
}