前言
好久没打cf的弟弟重新打cf了,由于fst一题没能上太多分。
ljjq
r
a
t
i
n
g
+
=
65
rating+=65
rating+=65 1720->1785
A. Optimal Currency Exchange
题意
签到题。
做法
暴力枚举即可。
代码
#include<stdio.h>
int min(int a,int b) {return a<b?a:b;}
int main()
{
int n,d,e;
scanf("%d%d%d",&n,&d,&e);
e = 5*e;
int ans = n;
for(int i=0;i<=n/d;i++) ans=min(ans,(n-i*d)%e);
printf("%d\n",ans);
return 0;
}
B. Badges
题意
签到题。
做法
枚举男女生人数即可。
代码
#include<stdio.h>
int main()
{
int b,g,n;
scanf("%d%d%d",&b,&g,&n);
int ans = 0;
for(int i=0;i<=b;i++)
{
for(int j=0;j<=g;j++)
{
if(i+j==n)
{
ans++;
}
}
}
printf("%d\n",ans);
return 0;
}
C. Bad Sequence
题意
给你一个括号序列,问是否可以最多改变一个括号的位置使原序列变为合法序列。
做法
考虑判断一个括号序列是否合法的方法,就是把(当成1,)当成-1,前缀和之后看是否出现过小于0的前缀和,再判断最后的和是否为0.
这道题同理,我们只需要判断是否出现过小于-1的前缀和,最后判断和是否为0即可。
代码
#include<stdio.h>
const int maxn = 2e5+10;
char str[maxn];
int main()
{
int n;
scanf("%d",&n);
scanf("%s",str+1);
int sum = 0;
int flag=0;
for(int i=1;i<=n;i++)
{
if(str[i]=='(') sum++;
else sum--;
if(sum<-1) flag=1;
}
if(sum!=0) flag=1;
if(flag==0) puts("YES");
else puts("NO");
return 0;
}
D. Treasure Island
题意
给你一个地图,地图上有一些点是墙壁,最初你站在(1,1)这个点上,每一步只能向右或者向下,问如果为了不让你走到(n,m)这个点,最少添加几个墙壁。
做法
我们知道答案最大为2,因为我们只需要把(1,2)和(2,1)变成墙壁主角就无法走出去了。所以我们现在要判断的就是是否可以不添加或者添加1个墙壁使(1,1)不能走到(n,m)。
第一种情况只需要判断(1,1)是否可以走到(n,m)即可。
第二种情况我的做法是首先dp求出(1,1)这个点到每一个点(i,j)的方案数dp[i][j],并求出(i,j)这个点到达(n,m)这个点的方案数dp2[i][j]。
然后查找是否存在这样一个点(i,j)使得dp[i][j]*dp2[i][j] = dp[n][m],这个意思也就是说所有方案都要经过(i,j)这个点,我们只要把这个点变为墙即可。
但是由于这道n,m很大,所以需要对方案数取模,赛中用两个常用的质数取模被hack掉了。赛后随机了3个模数就过掉了(sad)。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<vector>
#include<random>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
string str[maxn];
char tmp[maxn];
int mod[10];
static int rand_int()
{
static std::mt19937 gen((std::random_device())());
static std::uniform_int_distribution<int> uid(1e8, 1e9);
return uid(gen);
}
int main()
{
int n,m;
for(int i=0;i<10;i++) mod[i] = rand_int();
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%s",tmp);
str[i] = tmp;
}
vector<vector<vector<ll> > > v(10);
for(int i=0;i<6;i++)
{
v[i].resize(n);
for(int j=0;j<n;j++)
v[i][j].resize(m);
}
for(int i=0;i<3;i++) v[i][0][0]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(str[i][j]=='#') continue;
if(i>0&&str[i-1][j]=='.')
{
for(int k=0;k<3;k++)
{
v[k][i][j]=(v[k][i][j]+v[k][i-1][j])%mod[k];
}
}
if(j>0&&str[i][j-1]=='.')
{
for(int k=0;k<3;k++)
{
v[k][i][j]=(v[k][i][j]+v[k][i][j-1])%mod[k];
}
}
}
}
for(int i=3;i<6;i++) v[i][n-1][m-1]=1;
for(int i=n-1;i>=0;i--)
{
for(int j=m-1;j>=0;j--)
{
if(str[i][j]=='#') continue;
if(i<n-1&&str[i+1][j]=='.')
{
for(int k=3;k<6;k++)
{
v[k][i][j]=(v[k][i][j]+v[k][i+1][j])%mod[k-3];
}
}
if(j<m-1&&str[i][j+1]=='.')
{
for(int k=3;k<6;k++)
{
v[k][i][j]=(v[k][i][j]+v[k][i][j+1])%mod[k-3];
}
}
}
}
if(v[0][n-1][m-1]==0)
{
printf("0\n");
return 0;
}
int flag=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(i==n-1&&j==m-1) continue;
if(i==0&&j==0) continue;
int f=0;
for(int k=0;k<3;k++)
{
if(1LL*v[k][i][j]*v[k+3][i][j]%mod[k]!=v[k][n-1][m-1]) f=1;
}
if(f==0) flag=1;
}
}
if(flag==0) printf("2\n");
else printf("1\n");
return 0;
}
E. Petya and Construction Set
题意
给你2n个点,构造一棵树,对于下标为2i-1的点和下标为2i的点有一个限制d[i],也就是2i-i这个点与2i这个点之间的路径长度要等于d[i]。
做法
首先把所有d从大到小排序,并且按顺序放在一个长度为n的链上,因为保证d非递增。所以我们只要从大到小不断加入每一个点即可,如果当前树链放不下这个关系,那么就延伸这个链,否则就在当前链加一条分支即可。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 2e5+10;
int d[maxn];
struct data
{
int pos;
int d;
bool operator < (const data &y)
{
return d>y.d;
}
}x[maxn];
int f[maxn];
int pos[maxn];
vector<int> v;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
x[i].pos=i*2-1;
scanf("%d",&x[i].d);
}
sort(x+1,x+1+n);
for(int i=1;i<=n;i++) pos[i] = x[i].pos;
v.push_back(pos[n]);
for(int i=1;i<=n-1;i++) printf("%d %d\n",pos[i],pos[i+1]);
for(int i=1;i<=n;i++)
{
int d = x[i].d;
int tt = i+d-1;
if(tt<n)
{
printf("%d %d\n",x[i].pos+1,pos[tt]);
}
else
{
int sz=v.size();
if(n-i+(int)v.size()-1==d-1)
{
printf("%d %d\n",x[i].pos+1,v[sz-1]);
v.push_back(x[i].pos+1);
}
else
{
printf("%d %d\n",x[i].pos+1,v[d-(n-i)-1]);
}
}
}
return 0;
}