前言
在晚上的div2之前打开的这场,但是自己头脑貌似不太清醒,全程在写bug,而且B题不知道自己在写啥,写了一百多行?,C也写了好多bug导致最后的D一眼思路但是没写完。希望晚上状态不要这么差!QWQ
A. Golden Plate
题意
给你一个h*w的长方形边框,每减小一次h-=4,w-=4,问从当前大小减小k-1次,
总的周长是多少
做法
直接模拟
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int vis[105];
int vis2[105];
int main()
{
int n,x,y;
scanf("%d",&n);
scanf("%d",&x);
while(x--)
{
scanf("%d",&y);
vis[y]=1;
}
for(int i=1;i<=n-1;i++)
{
scanf("%d",&x);
for(int j=1;j<=100;j++) vis2[j]=0;
while(x--)
{
scanf("%d",&y);
vis2[y]=1;
}
for(int j=1;j<=100;j++)
{
if(vis[j]&&vis2[j]) vis[j]=1;
else vis[j]=0;
}
}
for(int i=1;i<=100;i++) if(vis[i]) printf("%d ",i);
printf("\n");
return 0;
}
B. Curiosity Has No Limits
题意
题意就是给你一个A序列和一个B序列
让你构造一个t序列,t序列满足
a
i
=
t
i
∣
t
i
+
1
a_i=t_i|t_{i+1}
ai=ti∣ti+1
b
i
=
t
i
b_i=t_i
bi=ti&
t
i
+
1
t_{i+1}
ti+1
做法
赛中自己没什么想法,于是就写了个dp
dp[i][j]表示第i个位置放j是否合法,之后就暴力跑就可以了
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn = 1e5+5;
int dp[maxn][4];
int pre[maxn][4];
int t[maxn];
int a[maxn],b[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n-1;i++) scanf("%d",&a[i]);
for(int i=1;i<=n-1;i++) scanf("%d",&b[i]);
for(int i=0;i<=3;i++) dp[1][i]=1;
int flag=0;
for(int i=2;i<=n;i++)
{
if(a[i-1]==0)
{
if(b[i-1]==0)
{
if(dp[i-1][0])
{
pre[i][0]=0;
dp[i][0]=1;
}
}
else
{
flag=1;
break;
}
}
else if(a[i-1]==1)
{
if(b[i-1]==2||b[i-1]==3)
{
flag=1;
break;
}
else if(b[i-1]==0)
{
if(dp[i-1][0])
{
pre[i][1]=0;
dp[i][1]=1;
}
if(dp[i-1][1])
{
pre[i][0]=1;
dp[i][0]=1;
}
}
else
{
if(dp[i-1][1])
{
pre[i][1]=1;
dp[i][1]=1;
}
}
}
else if(a[i-1]==2)
{
if(b[i-1]==1||b[i-1]==3)
{
flag=1;
break;
}
else if(b[i-1]==0)
{
if(dp[i-1][0])
{
pre[i][2]=0;
dp[i][2]=1;
}
if(dp[i-1][2])
{
pre[i][0]=2;
dp[i][0]=1;
}
}
else
{
if(dp[i-1][2])
{
pre[i][2]=2;
dp[i][2]=1;
}
}
}
else
{
if(b[i-1]==0)
{
if(dp[i-1][0])
{
pre[i][3]=0;
dp[i][3]=1;
}
if(dp[i-1][1])
{
pre[i][2]=1;
dp[i][2]=1;
}
if(dp[i-1][2])
{
pre[i][1]=2;
dp[i][1]=1;
}
if(dp[i-1][3])
{
pre[i][0]=3;
dp[i][0]=1;
}
}
else if(b[i-1]==1)
{
if(dp[i-1][1])
{
pre[i][3]=1;
dp[i][3]=1;
}
if(dp[i-1][3])
{
pre[i][1]=3;
dp[i][1]=1;
}
}
else if(b[i-1]==2)
{
if(dp[i-1][2])
{
pre[i][3]=2;
dp[i][3]=1;
}
if(dp[i-1][3])
{
pre[i][2]=3;
dp[i][2]=1;
}
}
else
{
if(dp[i-1][3])
{
pre[i][3]=3;
dp[i][3]=1;
}
}
}
}
int tt=0;
for(int i=0;i<=3;i++)
{
if(dp[n][i]) tt=1;
}
if(flag==1||tt==0)
{
printf("NO\n");
return 0;
}
else
{
for(int i=0;i<=3;i++)
{
if(dp[n][i]) t[n]=i;
}
for(int i=n-1;i>=1;i--)
{
t[i]=pre[i+1][t[i+1]];
}
printf("YES\n");
for(int i=1;i<=n;i++) printf("%d ",t[i]);
}
return 0;
}
C. Cram Time
题意
给你两个数a,b,用a,b分别构造两个序列A,B,
要求A序列的和小于a,B序列的和小于b
而且A序列中和B序列中每个数最多在两个序列中出现一次
要是最终的两个序列的长度和最大,输出两个序列
做法
判
断
出
a
+
b
能
够
造
的
的
最
大
的
1
+
2
+
3
+
.
.
.
+
n
判断出a+b能够造的的最大的1+2+3+...+n
判断出a+b能够造的的最大的1+2+3+...+n
如果a+b>=(1+2+3+…n),一定可以构造出(1+2+3+…n)
至于构造方法,就先用a,b中大的数从大到小选,再用小的从大到小选,就OK了!
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
ll a,b;
vector<int> v1,v2;
int vis[maxn];
int main()
{
scanf("%lld%lld",&a,&b);
ll sum=a+b;
ll pos=0;
for(ll i=0;;i++)
{
if((1LL*i*(i+1))/2==sum)
{
pos=i;
break;
}
else if((1LL*i*(i+1))/2>sum)
{
pos=i-1;
break;
}
}
ll maxx=max(a,b);
ll minn=min(a,b);
ll tmp=sum-(1LL*pos*(pos+1))/2;
for(int i=pos;i>=1;i--)
{
if(maxx>=i)
{
v1.push_back(i);
maxx-=(i);
vis[i]=1;
}
}
for(int i=pos;i>=1;i--)
{
if(vis[i]) continue;
if(minn>=i)
{
v2.push_back(i);
vis[i]=1;
minn-=i;
}
}
if(a>=b)
{
printf("%d\n",v1.size());
for(int i=0;i<v1.size();i++) printf("%d ",v1[i]);
printf("\n%d\n",v2.size());
for(int i=0;i<v2.size();i++) printf("%d ",v2[i]);
}
else
{
printf("%d\n",v2.size());
for(int i=0;i<v2.size();i++) printf("%d ",v2[i]);
printf("\n%d\n",v1.size());
for(int i=0;i<v1.size();i++) printf("%d ",v1[i]);
}
return 0;
}
D. Minimum path
题意
给你一个字符矩阵,起点在左上角,每次可以向右或者向下走,可以改变这个字符矩阵中的k个字符,是这个路径构成的字符串字典序最小。
做法
由于可以改变k个字符,那么肯定是找到一条路径,前面至少有k项为a,
后面按照字典序选择路径就可以。
所以我们先用dp[i][j]表示从原点到(i,j)的路径中a最多有多少个。
之后对所有dp[i][j]-(i+j-1)>=k的点中选一个(i+j-1)最大的,
也就是能让前缀全是a的最长前缀,然后把所有满足的丢进vector
用滚动的vector每次选出往后走的字典序最小的,再丢尽vector
对每个点存一下他的上一个点,pre[i][j]
走到最后vector的大小为1,也就是走到终点,
最后通过pre[i][j]逆序输出答案
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
const int maxn = 2005;
int n,k,dp[maxn][maxn];
int vis[maxn][maxn];
pii mp[maxn][maxn];
char pic[maxn][maxn];
vector<pii> ans[2];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%s",pic[i]+1);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(pic[i][j]=='a')
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1])+1;
}
else
{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
k=min(k,2*n-1);
int maxx=k;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(dp[i][j]>=(i+j-1)-k) maxx=max(maxx,i+j-1);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(dp[i][j]>=(i+j-1)-k&&(i+j-1)==maxx)
{
ans[0].push_back(pii(i,j));
}
}
}
string tmp="";
for(int i=1;i<=maxx;i++) tmp+='a';
int left;
if(tmp=="")
{
left=2*n-2;
ans[0].push_back(pii(1,1));
}
else
{
left=2*n-1-maxx;
}
for(int i=0;i<left;i++)
{
int minn=25;
for(int j=0;j<ans[i%2].size();j++)
{
int stx=ans[i%2][j].first;
int sty=ans[i%2][j].second;
if(stx<n) minn=min(minn,pic[stx+1][sty]-'a');
if(sty<n) minn=min(minn,pic[stx][sty+1]-'a');
}
ans[(i+1)%2].clear();
for(int j=0;j<ans[i%2].size();j++)
{
int stx=ans[i%2][j].first;
int sty=ans[i%2][j].second;
if(stx<n)
{
if(pic[stx+1][sty]-'a'==minn&&!vis[stx+1][sty])
{
vis[stx+1][sty]=1;
mp[stx+1][sty]=pii(stx,sty);
ans[(i+1)%2].push_back(pii(stx+1,sty));
}
}
if(sty<n)
{
if(pic[stx][sty+1]-'a'==minn&&!vis[stx][sty+1])
{
vis[stx][sty+1]=1;
mp[stx][sty+1]=pii(stx,sty);
ans[(i+1)%2].push_back(pii(stx,sty+1));
}
}
}
}
string ans="";
int sx=n,sy=n;
while(sx+sy-1>maxx)
{
ans+=pic[sx][sy];
pii tmp=mp[sx][sy];
sx=tmp.first;
sy=tmp.second;
}
reverse(ans.begin(),ans.end());
tmp+=ans;
printf("%s\n",tmp.c_str());
return 0;
}