补题链接
本来都是能写题,代码没写好,导致没能拿满分 打A组的人太少了。。
D-迷宫
题目:
做法:简单bfs
我bfs 写挫了。。。
主要是这个样例:
11011
10101
10101
10001
11011
#include<bits/stdc++.h>
using namespace std;
const int N=35,M=55;
char s[N][M];
int n,m,vis[N][N],mi,ans;
struct node
{
int x,y,t;
};
int dir[4][2]={0,1,1,0,0,-1,-1,0};
void bfs()
{
queue<node>que;
for(int i=1;i<=m;++i) {
if(s[1][i]=='1') continue;
que.push({1,i,0});
vis[1][i]=1;
}
mi=3000;
while(que.size())
{
node now=que.front();que.pop();
if(now.x==n){
if(now.t==mi) ans++;
else if(now.t<mi) mi=now.t,ans=1;
}
for(int i=0;i<4;++i){
int x=now.x+dir[i][0];
int y=now.y+dir[i][1];
if(x<1||y<1||x>n||y>m) continue;
if(s[x][y]=='1')continue;
if(now.t+1>vis[x][y]) continue;
vis[x][y]=now.t+1;
que.push({x,y,now.t+1});
}
}
}
int main()
{
n=30,m=50;
for(int i=1;i<=n;++i){
scanf("%s",s[i]+1);
}
//--n;
mi=0x3f3f3f3f;
memset(vis,0x3f3f3f3f,sizeof(vis));
bfs();
printf("mi:%d ans:%d\n",mi,ans);
}
/*
01010101001011001001010110010110100100001000101010
00001000100000101010010000100000001001100110100101
01111011010010001000001101001011100011000000010000
01000000001010100011010000101000001010101011001011
00011111000000101000010010100010100000101100000000
11001000110101000010101100011010011010101011110111
00011011010101001001001010000001000101001110000000
10100000101000100110101010111110011000010000111010
00111000001010100001100010000001000101001100001001
11000110100001110010001001010101010101010001101000
00010000100100000101001010101110100010101010000101
11100100101001001000010000010101010100100100010100
00000010000000101011001111010001100000101010100011
10101010011100001000011000010110011110110100001000
10101010100001101010100101000010100000111011101001
10000000101100010000101100101101001011100000000100
10101001000000010100100001000100000100011110101001
00101001010101101001010100011010101101110000110101
11001010000100001100000010100101000001000111000010
00001000110000110101101000000100101001001000011101
10100101000101000000001110110010110101101010100001
00101000010000110101010000100010001001000100010101
10100001000110010001000010101001010101011111010010
00000100101000000110010100101001000001000000000010
11010000001001110111001001000011101001011011101000
00000110100010001000100000001000011101000000110011
10101000101000100010001111100010101001010000001000
10000010100101001010110000000100101010001011101000
00111100001000010000000110111000000001000000001011
10000001100111010111010001000110111010101101111000
*/
E-NP完全问题
做法:经典折半搜索 裸题了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=20;
int n=15;
map<ll,string>mp;
ll V=1019842928705602;
ll A[31]={0,
70368744177669, 105553116266503,
123145302310920, 61572651155460,
30786325577730, 15393162788865,
78065325572101, 109401406963719,
125069447659528, 62534723829764,
31267361914882, 15633680957441,
78185584656389, 109461536505863,
125099512430600, 62549756215300,
31274878107650, 15637439053825,
78187463704581, 109462476029959,
125099982192648, 62549991096324,
31274995548162, 15637497774081,
78187493064709, 109462490710023,
125099989532680, 62549994766340,
31274997383170, 15637498691585};
void dfs1(int id,ll sum, string s)
{
if(id>15){
mp[sum]=s;
return ;
}
dfs1(id+1,sum+A[id],s+'1');
dfs1(id+1,sum,s+'0');
}
string ans;
void dfs2(int id,ll sum, string s)
{
if(id>30){
if(mp.count(V-sum)!=0){
ans=mp[V-sum]+s;
}
return ;
}
dfs2(id+1,sum+A[id],s+'1');
dfs2(id+1,sum,s+'0');
}
int main()
{
dfs1(1,0,"");
dfs2(16,0,"");
cout<<ans<<endl;
}
/*
110010000011111110101001001001
*/
F-决斗
水题一个,根据题意模拟一下就可以了。
G-学习
也是水题,排下序就可以了。
H-数字游戏
做法:dp一下就可以了,
dp[i][j]
j ==0 前i个子区间乘法为0的个数
j ==1 前i个子区间乘法大于0的个数
j ==2 前i个子区间乘法小于0的个数
维护每个负数前面正数的个数f2[2] 数组
维护每个0前面的数
细节很多,看代码的转移方程吧,我有个小细节没写好,导致坑了。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e6+10;
ll dp[N][3];//0:等于0 1:大于0 2 :于0
ll f2[2];//负数的交叉
ll pre;//前缀和
ll f0[2];//0的交叉
int n,m;
int main()
{
scanf("%d%d",&n,&m);
int now=0;
for(int i=1;i<=n;++i){
int x;
scanf("%d",&x);
for(int j=0;j<3;++j) dp[i][j]=dp[i-1][j];
f0[0]++;
if(x==0){
f2[0]=0,f2[1]=0;
dp[i][0]+=i;
f0[1]=i;
}
else if(x>0){
f2[now]++;
dp[i][0]+=f0[1];
dp[i][1]+=f2[now];
dp[i][2]+=f2[now^1];
}
else{
f2[now]++;
dp[i][0]+=f0[1];
dp[i][1]+=f2[now^1];
dp[i][2]+=f2[now];
now^=1;
}
//printf("i:%d %lld %lld %lld\n",i,dp[i][1],dp[i][0],dp[i][2]);
}
while(m--){
int ty;
scanf("%d",&ty);
if(ty==2){
printf("%lld %lld %lld\n",dp[n][1],dp[n][0],dp[n][2]);
}
else{
int t;
scanf("%d",&t);
while(t--){
int x;
scanf("%d",&x);
for(int j=0;j<=2;++j) dp[n+1][j]=dp[n][j];
//for(int j=0;j<3;++j) dp[i][j]=dp[i-1][j];
f0[0]++;
if(x==0){
f2[0]=0,f2[1]=0;
dp[n+1][0]+=n+1;
f0[1]=n+1;
}
else if(x>0){
f2[now]++;
dp[n+1][0]+=f0[1];
dp[n+1][1]+=f2[now];
dp[n+1][2]+=f2[now^1];
}
else{
f2[now]++;
dp[n+1][0]+=f0[1];
dp[n+1][1]+=f2[now^1];
dp[n+1][2]+=f2[now];
now^=1;
}
++n;
}
}
}
}
/*
9 2
-1 1 0 -1 1 0 -1 1 0
2
*/
I-植物大战僵尸
做法:二分一下最高能的值,check一下即可。
这题我代码爆longlong了,所以没有满分,气死人
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
ll n,m;
ll a[N];
int cal(ll mid)
{
ll to=0;
ll res=0;
for(int i=1;i<n;++i){
++to;
++res;
ll t=0;
if(mid>to*a[i]){
t=(mid-to*a[i])/a[i];
if((mid-to*a[i])%a[i]) ++t;
}
res+=t*2;
to=t;
}
if(mid>to*a[n]){
ll t=(mid-to*a[n])/a[n];
if((mid-to*a[n])%a[n]) ++t;
--t;
res++;
res+=t*2;
}
//printf("mid:%lld res:%lld\n",mid,res);
return res<=m;
}
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
cin>>n>>m;
ll mi=(1ll<<62),mx=0;
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
mi=min(mi,a[i]);
}
if(m<=n){
if(m==n) printf("%lld\n",mi);
else printf("0");
return 0;
}
ll l=0,r=1e12,ans=0;
//puts("****");
while(l<=r)
{
ll mid=l+r>>1;
if(cal(mid)) {
//printf("mid:%lld\n",mid);
ans=mid,l=mid+1;
}
else r=mid-1;
}
printf("%lld\n",ans);
}
J-魔法青蛙
简单dp,dp[i]为前i个的最大值,容易想到两层for循环转移方程:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N],b[N],n,m;
ll dp[N];
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
cin>>n>>m;
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i) scanf("%d",&b[i]);
ll ans=0;
for(int i=1;i<=n;++i){
dp[i]=b[i];
for(int j=1;j<i;++j){
if(a[i]%2==a[j]%2) continue;
if(a[j]+m<a[i]) continue;
//printf("i:%d j:%d\n",i,j);
dp[i]=max(dp[i],dp[j]+b[i]);
}
ans=max(ans,dp[i]);
//printf("i:%d:%lld\n",i,dp[i]);
}
printf("%lld\n",ans);
}
考虑把第二层for循环用线段树维护一下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int a[N],b[N],n,m,M;
ll dp[N];
ll mx[2][4*N];
void up(int id,int l,int r,int pos,ll val,int ty)
{
if(l==r){
mx[ty][id]=max(mx[ty][id],val);
return ;
}
int mid=l+r>>1;
if(pos<=mid) up(id<<1,l,mid,pos,val,ty);
else up(id<<1|1,mid+1,r,pos,val,ty);
mx[ty][id]=max(mx[ty][id<<1],mx[ty][id<<1|1]);
}
ll qu(int id,int l,int r,int ql,int qr,int ty)
{
if(ql<=l&&r<=qr){
return mx[ty][id];
}
ll res=0;
int mid=l+r>>1;
//printf("id:%d l:%d r:%d\n",id,l,r);
if(ql<=mid) res=qu(id<<1,l,mid,ql,qr,ty);
if(qr>mid) res=max(res,qu(id<<1|1,mid+1,r,ql,qr,ty));
return res;
}
int main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
M=2e5+10;
cin>>n>>m;
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i) scanf("%d",&b[i]);
ll ans=0;
for(int i=1;i<=n;++i){
if(a[i]%2){
ll mx=qu(1,1,M,max(1,a[i]-m),M,0);
dp[i]=mx+b[i];
up(1,1,M,a[i],dp[i],1);
}
else{
ll mx=qu(1,1,M,max(1,a[i]-m),M,1);
dp[i]=mx+b[i];
up(1,1,M,a[i],dp[i],0);
}
ans=max(ans,dp[i]);
//printf("i:%d dp:%lld\n",i,dp[i]);
}
printf("%lld\n",ans);
}