2022南外集训 Day5
作者:互联网
杂言
今天没啥好说哒,八道题,感觉能至少A5道,状态还算好,可是只有450pts
改题改题,练就完了
T1 俄罗斯国旗
看到 \(n<=50\) 直接 \(n^4\)搞起
枚举主要是枚举颜色不同的分界线行
T1 accept
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const int maxn=55;
inline int read()
{
int x=0,y=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') y=-1; c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int n,m;
char s[maxn][maxn];
int ans(0);
int check(int l1,int l2)
{
int cnt(0);
for(int i=1;i<l1;i++)
for(int j=1;j<=m;j++)
if(s[i][j]!='W') cnt++;
for(int i=l1;i<l2;i++)
for(int j=1;j<=m;j++)
if(s[i][j]!='B') cnt++;
for(int i=l2;i<=n;i++)
for(int j=1;j<=m;j++)
if(s[i][j]!='R') cnt++;
return cnt;
}
int main()
{
n=read(); m=read();
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);
ans=inf;
for(int i=2;i<n;i++)
for(int j=i+1;j<=n;j++)
ans=min(ans,check(i,j));
printf("%d\n",ans);
return 0;
}
T2 哞哞哞~~
有一个无限长的字母序列。
定义如下:令S[0]="moo"。一个更长的S[k]开头的一段为S[k-1],之后为“mo...oo”,包含k+2个“o”,接下来再为一段S[k-1]。
如:
S[0]=“moo”
S[1]=“moomooomoo”
S[2]="moomooomoomoooomoomooomoo"
……
这样就可以造出一个无限长的字母序列。
现在问你,序列中第n个字母是“m”还是“o”。
安心预处理,然后递归就行
T2 accept
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1e3+5;
inline int read()
{
int x=0,y=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') y=-1; c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int n;
int vec[maxn];
void dfs(int u,int x)
{
if(!u) return ;
//cout<<x<<" "<<u<<" qwq\n";
if(x>vec[u-1]&&x<=u+1+vec[u-1])
if(x==vec[u-1]+1) {printf("m"); return ;}
else {printf("o"); return ;}
if(x<=vec[u-1]) dfs(u-1,x);
else dfs(u-1,x-(u+1+vec[u-1]));
return ;
}
int main()
{
n=read();
for(int i=0,j=3;;i=vec[vec[0]]*2+j,j++)
{vec[++vec[0]]=i; if(i>=n) break;}
dfs(vec[0],n);
return 0;
}
T3 挤奶
小X的 N 头奶牛要挤奶 N∈[1,10000].为了方便编号1…N.每头奶牛挤奶耗时T[i] .但是有些奶牛一定要在另一头奶牛前挤奶。为了加快挤奶速度,小X雇佣了无限个农场工人。可以同时挤奶,求最少的时间挤完所有奶。
考虑每次的限制关系就是一个有向边,满足拓扑序
那么直接 topsort,然后考场读题读错了耽误了一会(
T3 accept
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1e4+5;
inline ll read()
{
ll x=0,y=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') y=-1; c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int n,k;
ll tme[maxn];
struct edge
{
int to,next;
}g[maxn*5];
int head[maxn],cnt(0);
inline void add(int a,int b)
{
g[++cnt].to=b;
g[cnt].next=head[a];
head[a]=cnt;
return ;
}
int in[maxn];
ll p[maxn];
ll sum,ans(0);
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) tme[i]=read();
for(int i=1;i<=k;i++)
{
int u,v;
u=read(),v=read();
add(u,v); in[v]++;
}
queue<int> q;
for(int i=1;i<=n;i++) if(!in[i]) q.push(i);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=head[u];i;i=g[i].next)
{
int v=g[i].to;
p[v]=max(p[u]+tme[u],p[v]);
in[v]--;
if(!in[v]) q.push(v);
}
}
for(int i=1;i<=n;i++) ans=max(ans,p[i]+tme[i]);
printf("%lld\n",ans);
return 0;
}
/*8 8
1 2 3 1 1 1 3 4
1 2
1 3
2 4
3 4
5 1
6 1
4 7
4 8
*/
T4 最大数maxnumber
现在请求你维护一个数列,要求提供以下两种操作:
1、 查询操作。语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。
2、 插入操作。语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。
限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个数
(不许使用线段树)
考虑每次都是从后往前查,考虑st表,那么每次加入数只会影响最后一位的 \(O(logn)\) 更新
状态我设的就是: \(f[i][j]表示从i往回走 2^j 的区间的最大值\)
T4 accept
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=2e5+5;
inline int read()
{
int x=0,y=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') y=-1; c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int m,d,n;
char s[10];
int val[maxn],ans(0),Log[maxn];
int f[maxn][20];
int main()
{
m=read(); d=read(); Log[0]=-1;
while(m--)
{
scanf("%s",s+1);
if(s[1]=='A')
{
int x=read();
val[++n]=(x+ans)%d; f[n][0]=val[n];
Log[n]=Log[n>>1]+1;
for(int j=1;(1<<j)<=n;j++)
f[n][j]=max(f[n][j-1],f[n-(1<<j-1)][j-1]);
}
else if(s[1]=='Q')
{
int L=read();
int l=n-L+1,r=n,k=Log[L];
printf("%d\n",ans=max(f[l+(1<<k)-1][k],f[r][k]));
}
}
return 0;
}
T5 安抚奶牛
农夫John重修栈栏的时候遗忘了一个洞,导致邪恶的奶牛Bessie带领着一众奶牛从这个洞里逃了出来!!!每一头奶牛在外面待一分钟,都会给John造成一亿的损失,这样下去用不了多久John就会倾家荡产。好在知道迟早会被抓回去的奶牛们只是待在一条直线上,并且在那欣赏着祖国的大好河山。John知道 每一只奶牛相对于他所在位置的距离P_i(-500000<=P_i<=500000,P_i!=0)他每分钟能走的距离为一,并且身为老司机的他能在瞬间安抚下一只牛使之不再造成损失。现求出农夫John最少要损失多少亿。
输入
第一行一个数N(N<=1000)表示逃跑的奶牛数;
接下来N行,每行一个数P_i表示奶牛相对John的位置
显然一眼dp,一眼状态,结果寄成50了
很显然,每次在 \([l,r]\) 区间时,最终肯定是处于边界,可能是\(l\)或\(r\)
正确性就是因为如果一个区间最终处于中间位置,肯定是折回来的,肯定不优
因此状态就是 \(dp[i][j][1/0]\) 表示当前在左/右端点,的最小花费
更新显然:
用 \(dp[i+1][j][0/1]和dp[i][j-1][0/1]\) 更新 \(dp[i][j][0/1]\) 即可
然后我寄了(
先放代码
T5 50pts
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1e3+5;
inline int read()
{
int x=0,y=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') y=-1; c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int n,pos[maxn];
int dp[maxn][maxn][2];
int f[maxn][maxn][2];
int main()
{
n=read();
for(int i=1;i<=n;i++) pos[i]=read();
sort(pos+1,pos+1+n);
memset(dp,0x3f,sizeof(dp));
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++)
{
dp[i][i][1]=dp[i][i][0]=abs(pos[i]);
f[i][i][1]=f[i][i][0]=abs(pos[i]);
}
for(int len=2;len<=n;len++)
{
for(int i=1;i+len-1<=n;i++)
{
int j=i+len-1;
if(dp[i][j][0]>f[i+1][j][1]+dp[i+1][j][1]+pos[j]-pos[i])
dp[i][j][0]=dp[i+1][j][1]+f[i+1][j][1]+pos[j]-pos[i],
f[i][j][0]=f[i+1][j][1]+pos[j]-pos[i];
else if(dp[i][j][0]==f[i+1][j][1]+dp[i+1][j][1]+pos[j]-pos[i])
f[i][j][0]=min(f[i+1][j][1]+pos[j]-pos[i],f[i][j][0]);
if(dp[i][j][0]>f[i+1][j][0]+dp[i+1][j][0]+pos[i+1]-pos[i])
dp[i][j][0]=dp[i+1][j][0]+f[i+1][j][0]+pos[i+1]-pos[i],
f[i][j][0]=f[i+1][j][0]+pos[i+1]-pos[i];
else if(dp[i][j][0]==f[i+1][j][0]+dp[i+1][j][0]+pos[i+1]-pos[i])
f[i][j][0]=min(f[i+1][j][0]+pos[i+1]-pos[i],f[i][j][0]);
if(dp[i][j][1]>f[i][j-1][1]+dp[i][j-1][1]+pos[j]-pos[j-1])
dp[i][j][1]=f[i][j-1][1]+dp[i][j-1][1]+pos[j]-pos[j-1],
f[i][j][1]=f[i][j-1][1]+pos[j]-pos[j-1];
else if(dp[i][j][1]==f[i][j-1][1]+dp[i][j-1][1]+pos[j]-pos[j-1])
f[i][j][1]=min(f[i][j][1],f[i][j-1][1]+pos[j]-pos[j-1]);
if(dp[i][j][1]>f[i][j-1][0]+dp[i][j-1][0]+pos[j]-pos[i])
dp[i][j][1]=f[i][j-1][0]+dp[i][j-1][0]+pos[j]-pos[i],
f[i][j][1]=f[i][j-1][0]+pos[j]-pos[i];
else if(dp[i][j][1]==f[i][j-1][0]+dp[i][j-1][0]+pos[j]-pos[i])
f[i][j][1]=min(f[i][j][1],f[i][j-1][0]+pos[j]-pos[i]);
}
}
printf("%d\n",min(dp[1][n][1],dp[1][n][0]));
return 0;
}
考虑这样为什么有问题,我们用来转移的\(f\)数组,每次转移一定是跟随\(dp\)数组保持最优转移,但是\(f\)本身可能不是最优情况,因此会导致后面的 \(dp\) 数组更新出现问题
那么怎么保证计算没问题?
费用提前计算
每次我们走出的距离 \(x\) 会给剩下的所有点增加 \(x\) 的等待时间,因此如果当前从一个 \(len-1\) 的区间转移到一个 \(len\) 长度区间,那么添加之后剩下点和当前选的点会给出 \((n-len+1)*x\) 的花费 (相当于之前选过的 \(len-1\) 个点没加花费
这玩意老师说非常基础,我觉得没有非常( wtcl
上代码:
T5 accept
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1e3+5;
inline int read()
{
int x=0,y=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') y=-1; c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int n,pos[maxn];
int dp[maxn][maxn][2];
int main()
{
n=read();
for(int i=1;i<=n;i++) pos[i]=read();
sort(pos+1,pos+1+n);
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++) dp[i][i][1]=dp[i][i][0]=abs(pos[i])*n;
for(int len=2;len<=n;len++)
{
for(int i=1;i+len-1<=n;i++)
{
int j=i+len-1;
dp[i][j][0]=min(dp[i+1][j][0]+(pos[i+1]-pos[i])*(n-len+1),dp[i][j][0]);
dp[i][j][0]=min(dp[i+1][j][1]+(pos[j]-pos[i])*(n-len+1),dp[i][j][0]);
dp[i][j][1]=min(dp[i][j-1][0]+(pos[j]-pos[i])*(n-len+1),dp[i][j][1]);
dp[i][j][1]=min(dp[i][j-1][1]+(pos[j]-pos[j-1])*(n-len+1),dp[i][j][1]);
}
}
printf("%d\n",min(dp[1][n][1],dp[1][n][0]));
return 0;
}
标签:typedef,int,Day5,pos,long,南外,2022,include,dp 来源: https://www.cnblogs.com/mastey/p/16459554.html