Codeforces Round #139 (Div. 2) 题解
vp上古场次ing
CF225A Dice Tower
1.题目简述:
有 \(n\) 个骰子被叠在了一起。对于每个骰子上的一个数,与它对面的数的和始终为 \(7\) 。
你是小明,你只能从正面看这个骰子塔,你看到了每一个骰子的两面 \(a\) 与 \(b\) 。以及最顶上的数。
试问是否有可能用正常的骰子叠出描述中的骰子塔?
如果可以输出 \(\text{YES}\) ,否则输出 \(\text{NO}\) 。
2.解析:
问你是否能用正常的骰子堆出描述中的塔,那就是判断是否这个塔里会有不正常的骰子,也就是不是每个面的数字互不相同。
我们发现我们知道了顶上骰子的三个面,那么我们根据面对面的数字和为 \(7\) 。可以把第一个骰子的六面确定。
然后,这时第二个骰子的六面中也有三面被确定了。然后就可以往下做。
那么我们就只需要判定是否有一个骰子中有两面是相同的。
由于我们已知合法两面,那我们只用判断这两面是否有一面的值为骰子的顶部元素或者骰子的底部元素即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 300;
int n,x,y;
struct node{
int a,b;
}f[N];
signed main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
cin>>n>>x;
y=7-x;
for(int i=1;i<=n;i++){
cin>>f[i].a>>f[i].b;
if(f[i].a==x||f[i].a==y){
printf("NO");return 0;
}
if(f[i].b==x||f[i].b==y){
printf("NO");return 0;
}
}
printf("YES");
return 0;
}
CF225B Well-known Numbers
1.题目描述:
将一个数拆成若干个 \(k\) 阶斐波那契数的和,要求总数不小于 \(2\) 。
2.解析:
我们都知道传统的斐波那契数列是 \(f_i=f_{i-1}+f_{i-2}\) 。是将前两个数加起来作为自己的值。而扩展的斐波那契数列就是将自己的前 \(k\) 个数加起来作为自己的值。
然后在 \(f_k\) 之前的数为 \(0\) , \(f_k=1\) 。
我们发现 \(k\) 很大。直接去求就死了。
那么我们可以把 \(k\) 当为 \(1\) ,然后所有数减去一个 \(k\) 。
这样就是从 \(0\) 开始了,然后因为在 \(k\) 之前的数都为 \(0\) 。
所以不需要考虑这些数的值,然后计算每个 \(f\) 就做前缀和就完事了。
然后因为我们知道斐波那契数在几千次后已经很大了,同理的我们只用求几千次的 \(k\) 阶斐波那契数,然后从大到小往下取。
如果取出来,个数不满,那就加上 \(0\) 就是了。
因为 \(0\) 也是一个满足要求的斐波那契数。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 50000;
int sum,k,s[N],f[N],tot,ans[N],num;
signed main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
cin>>sum>>k;
//你模拟一下,就发现他就是加前面的k个
f[0]=0;f[1]=1;f[2]=1;
s[0]=0;s[1]=1;s[2]=2;
int g=0;
for(int i=3;i<=4000;i++){
int it=max(i-k,(int)1);
f[i]=s[i-1]-s[it-1];
s[i]=s[i-1]+f[i];
if(f[i]<0){
g=i-1;
break;
}
}
for(int i=g;i>=1;i--){
if(sum>=f[i]){
sum-=f[i];
ans[++num]=f[i];
}
}
if(num<=2){
ans[++num]=0;
}
sort(ans+1,ans+num+1);
cout<<num<<"\n";
for(int i=1;i<=num;i++){
cout<<ans[i]<<" ";
}
return 0;
}
CF225C Barcode
1.题目描述:
有一个方阵,要让每一列的颜色相同。然后连续相同的颜色列数在 \(x\) 与 \(y\) 之间。求最少的染色数。
2.解析:
这是一道有意思的 dp ,给了我一些启发。
你发现这个有一个有意思的限制,它要求了连续相同的颜色列数有一个范围。那你要考虑取限制这个东西。
怎么限制啊,感觉不太好限制。
后面想了一下,你可以这样来设立状态为 dp[i][0/1] 表示的是当前考虑到了第 \(i\) 列,染色为白色或者黑色的最少颜色数。
那接下来我们直接枚举从往后染 \(x\) 与 \(y\) 之间的列数为同一颜色。也就是把整个图划分为相邻颜色不同的矩形。
我们设 \(j\) 表示往后面染 \(j\) 列为同一颜色。
那么可以写出状态转移方程为:
然后就解决了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2060;
int n,m,x,y,a[N][N],s[N],t[N],ans,vis[N];
int dp[N][3];
signed main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
cin>>n>>m>>x>>y;
for(int i=1;i<=n;i++){
string ssh;
cin>>ssh;
for(int j=0;j<m;j++){
if(ssh[j]=='#') s[j+1]++;
else t[j+1]++;
}
}
for(int j=1;j<=m;j++){
s[j]+=s[j-1];t[j]+=t[j-1];
}
memset(dp,127,sizeof(dp));
dp[0][0]=dp[0][1]=0;
for(int i=0;i<m;i++){
for(int j=x;j<=y;j++){
if(i+j>m) break;
dp[i+j][0]=min(dp[i+j][0],dp[i][1]+s[i+j]-s[i]);
dp[i+j][1]=min(dp[i+j][1],dp[i][0]+t[i+j]-t[i]);
}
}
cout<<min(dp[m][0],dp[m][1]);
return 0;
}
CF225D Snake
1.题目描述:
贪吃蛇
2.解析:
这道题真的很强,不愧是 \(2200\) 的分,我开始想了一下,觉得这道题就是一个傻逼的要死的 bfs ,然后注意判断就可以了,然后直接提交。 发现 \(WA\) \(on\) \(53\) 原来是因为如果直接判读回去的不行,那么就会在某些特殊情况下失败,可以自己模拟一下。这里不详细赘述。然后看了官方题解,教我用状压来做,然后就状压 \(BFS\) 就行了。 最后因为你是用的4位状压,注意各种位移操作都要再乘上2。然后就完了,难点在于想到怎么状压,不过好像CF上有人用的 \(hash\) ? 反正很神奇
另外,此题是我改变码风的第一题/cy
#include<bits/stdc++.h>
using namespace std;
int n,m,a[15][15],in[15][15],dp[15][15][1<<16];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int tx,ty,ux[20],uy[20],s,tag;
struct snake{int x,y,t;};
int get(int nx,int ny,int rx,int ry){
for(int i=0;i<4;i++)
if(nx+dx[i]==rx&&ny+dy[i]==ry) return i;
return 0;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
char ch;
cin>>ch;
a[i][j]=ch;
if('1'<=ch&&ch<='9'){
ux[ch-'1']=i;
uy[ch-'1']=j;
s=max(ch-'0',s);
}
else if(ch=='@'){tx=i;ty=j;}
}
}
int st=0,mask=(1<<(2*s-2))-1,sx=ux[0],sy=uy[0];
for(int i=1;i<s;i++) st|=get(ux[i],uy[i],ux[i-1],uy[i-1])<<(i*2-2);
queue<snake>q;
q.push(snake{sx,sy,st});
memset(dp,-1,sizeof(dp));
dp[sx][sy][st]=0;
while(q.size()){
snake now=q.front();q.pop();
int x=now.x,y=now.y,t=now.t;
int nx=x,ny=y,nt=t;
in[x][y]=++tag;
for(int i=2;i<s;i++){
int d=(nt&3)^2;
nx+=dx[d];ny+=dy[d];
nt>>=2;
in[nx][ny]=tag;
}
for(int i=0;i<4;i++){
int xx=x+dx[i];
int yy=y+dy[i];
int dt=((t<<2)&mask)|i;
if(xx<0||yy<0||xx>=n||yy>=m||in[xx][yy]==tag||a[xx][yy]=='#'||~dp[xx][yy][dt]) continue;
dp[xx][yy][dt]=dp[x][y][t]+1;
q.push(snake{xx,yy,dt});
}
}
int ans=INT_MAX;
for(int i=0;i<1<<16;i++){
if(~dp[tx][ty][i]) ans=min(ans,dp[tx][ty][i]);
}
if(ans==INT_MAX) ans=-1;
cout<<ans;
return 0;
}