A.出题
分析:首先如果有解,必满足\(6 \times m \leq n \leq 9 \times m\),我们设6的个数为\(X\),则剩余的个数为\(m-X\),剩余的分值为\(n-6 \times X\),所以此时满足条件必有如下式子:\(7 \times (m-X) \leq n-6 \times X \leq 9 \times (m-X)\),化简以后最终所求为 \(max(0,7 \times m-n)\)
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
LL n,m;
int main()
{
scanf("%lld%lld",&n,&m);
if(n<6*m||(n>9*m)) printf("jgzjgzjgz\n");
else printf("%lld\n",max((LL)0,7*m-n));
return 0;
}
B.煤气灶
分析:用等差数列求和公式,然而求解一个一元二次方程,直接二分答案即可
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
LL n,m,d,x;
bool judge(LL k){
if((k*(k-1)*d)>=(2*m-2*n*k)) return true;
return false;
}
int main()
{
scanf("%lld%lld%lld%lld",&n,&m,&d,&x);
LL l=0,r=x,ans=x;
while(l<=r){
LL mid=(l+r)/2;
if(judge(mid)){
ans=mid;
r=mid-1;
}else l=mid+1;
}
printf("%lld\n",ans);
}
C.项链
分析:贪心尽量选择价值大的来匹配,注意存在n大于总价值的情况
#include "bits/stdc++.h"
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
struct node{
LL a,b;
}p[maxn];
int n,m;
bool cmp(node x,node y){
return x.b>y.b;
}
LL dp[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%lld",&p[i].a);
for(int i=1;i<=m;i++) scanf("%lld",&p[i].b);
sort(p+1,p+1+m,cmp);
for(int i=1;i<=m;i++){
dp[i]=dp[i-1]+p[i].a;
}
int pos=m;
for(int i=1;i<=m;i++){
if(dp[i]>=n){
pos=i; break;
}
}
LL sum=0;
for(int i=1;i<=pos-1;i++) sum+=p[i].a*p[i].b;
sum+=(n-dp[pos-1])*p[pos].b;
LL mx=0;
for(int i=1;i<=m;i++) mx+=p[i].a*p[i].b;
printf("%lld\n",min(mx,sum));
return 0;
}
D.美食
分析:不管当前是奇数还是偶数,都尽量用完,如果有剩余,就往下一个累计
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
const int maxn=1e5+100;
LL a[maxn];
int n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
LL sum=0;
for(int i=1;i<=n;i++){
sum+=a[i]/2;
if(a[i+1]>0&&(a[i]%2)){
sum++;
a[i+1]--;
}
}
printf("%lld\n",sum);
return 0;
}
E.海啸
分析:我们让小于d的为0,大于等于d的为0。这样很容易把问题转化为一个二维前缀和问题。二维前缀和的求解方法是:
预处理的时候有:
dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+a[i][j];
求解\((x_1,y_1)(x_2,y_2)\)构成的矩阵的和有
dp[x2][y2]-dp[x1-1][y2]-dp[x2][y1-1]+dp[x1-1][y1-1]
#include "bits/stdc++.h"
using namespace std;
int n,m,d,q;
int main()
{
scanf("%d%d%d",&n,&m,&d);
int a[n+10][m+10],dp[n+10][m+10];
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x; scanf("%d",&x);
if(x>=d) a[i][j]=1;
else a[i][j]=0;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+a[i][j];
}
int q;
scanf("%d",&q);
while(q--){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%d\n",dp[x2][y2]-dp[x1-1][y2]-dp[x2][y1-1]+dp[x1-1][y1-1]);
}
return 0;
}
F.石头剪刀布
分析:这题出得非常好,做法是思维+递归。首先,如果我们知道最后剩下的是哪个,一定可以通过DFS构造出这个序列。因为我们必然可以知道它本身和它可以打败的,在题目中,我们定义本身为i,则它可以打败的为(i+2)%3。然后我们在做一个字典序的判断即可。
#include "bits/stdc++.h"
using namespace std;
int P,R,S,p,r,s,L;
string dfs(int i,int l){
if(l==L){
if(i==0){++r,++s; return "RS";}
if(i==1){++p,++r; return "PR";}
if(i==2){++p,++s; return "PS";}
}
string a=dfs(i,l<<1),b=dfs((i+2)%3,l<<1);
if(a+b>b+a) return b+a;
return a+b;
}
int main()
{
scanf("%d%d%d",&R,&P,&S);
L=R+P+S;
for(int i=0;i<3;i++){
r=p=s=0;
string res=dfs(i,2);
if(r==R&&p==P&&s==S){
cout<<res<<endl;
return 0;
}
}
cout<<"IMPOSSIBLE"<<endl;
return 0;
}
G.区间或和
分析:这是一道很好的思维题,显然a=b的时候,答案就是a,那当a!=b的时候呢?首先我们求出a与b二进制下不同的最高位,显然根据或的性质,所有比这一位高的位都是原来的值。那么比这一位低的呢?因为取遍了[a,b]区间内的所有数,所以比它低的每一个二进制位至少有一个是0,所以比它低的位全为0
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
LL a,b;
int main()
{
while(scanf("%lld%lld",&a,&b)!=EOF){
LL c=a^b;
LL x=1;
while(x<=c) x*=2;
printf("%lld\n",a|b|x-1);
}
return 0;
}
H.肥猪
分析:首先枚举会进行2操作的次数step,则对于一个位置i,它如果由2操作变换过来,则它一定由j变换过来,同时\(i-step \leq j \leq i\)。所以我们只需要枚举在这个范围内最小的a[j]即可,这样在加上\(step \times X\),就是最终的结果。区间最小值用线段树维护一下即可
#include "bits/stdc++.h"
using namespace std;
const int maxn=2e3+100;
typedef long long LL;
struct node{
int left,right;
LL Min;
}tree[maxn<<2];
int n;
LL x;
void pushup(int rt){
tree[rt].Min=min(tree[rt<<1].Min,tree[rt<<1|1].Min);
}
void build(int l,int r,int rt){
tree[rt].left=l,tree[rt].right=r;
tree[rt].Min=INT64_MAX;
if(l==r){
scanf("%lld",&tree[rt].Min);
tree[rt].left=l,tree[rt].right=r;
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(rt);
}
LL query(int l,int r,int rt){
int L=tree[rt].left,R=tree[rt].right;
if(l==L&&r==R) return tree[rt].Min;
int mid=(L+R)>>1;
if(r<=mid) return query(l,r,rt<<1);
if(l>mid) return query(l,r,rt<<1|1);
return min(query(l,mid,rt<<1),query(mid+1,r,rt<<1|1));
}
int main()
{
scanf("%d%lld",&n,&x);
build(1,n,1);
LL ans=INT64_MAX;
for(int i=0;i<n;i++){
LL res=i*x;
for(int j=1;j<=n;j++){
if(j-i<1){
if(j-i==0) res+=min(query(1,j,1),query(n,n,1));
else res+=min(query(1,j,1),query((j-i+n)%n,n,1));
}else res+=query(j-i,j,1);
}
ans=min(ans,res);
}
printf("%lld\n",ans);
return 0;
}
I.wzoi
分析:这个题做法也很显然,用一个栈来维护,如果当前元素和栈顶相同,则+10分,否则把当前元素压栈。这样我们一定能把所有10分的全部求完,剩下栈中的部分一定是5分的。
#include "bits/stdc++.h"
using namespace std;
const int maxn=1e6+100;
string str;
int a[maxn];
int main()
{
cin>>str;
int n=str.length();
for(int i=1;i<=n;i++){
a[i]=str[i-1]-'0';
}
stack<int>s;
int sum=0;
for(int i=1;i<=n;i++){
if(s.empty()){
s.push(a[i]);
}else{
if(a[i]==s.top()){
sum+=10;
s.pop();
}else{
s.push(a[i]);
}
}
}
sum+=s.size()/2*5;
printf("%d\n",sum);
return 0;
}
J.迷宫
分析:直接BFS把队列跑空,则能够遍历到所有能达到的点,注意标记一下左右的次数
#include "bits/stdc++.h"
using namespace std;
const int maxn=1000+10;
int vis[maxn][maxn],n,m,r,c,x,y;
char s[maxn][maxn];
struct node{
int x,y;
int l,r;
}p[maxn*maxn];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
int ans;
bool judge(int a,int b){
if(a<1||a>n||b<1||b>m||s[a][b]=='*'||vis[a][b])
return false;
return true;
}
void bfs()
{
node t;
t.x=r,t.y=c;
t.l=x,t.r=y;
queue<node>que;
que.push(t);
vis[t.x][t.y]=1;
while(!que.empty()){
node tmp=que.front();
que.pop();
ans++;
vis[tmp.x][tmp.y]=1;
for(int i=0;i<4;i++){
int nx=tmp.x+dx[i];
int ny=tmp.y+dy[i];
if(judge(nx,ny)){
vis[nx][ny]=1;
node res;
if(i==0||i==1){
res.x=nx,res.y=ny;
res.l=tmp.l,res.r=tmp.r;
que.push(res);
}
if(i==2&&tmp.l){
res.x=nx,res.y=ny;
res.l=tmp.l-1,res.r=tmp.r;
que.push(res);
}
if(i==3&&tmp.r){
res.x=nx,res.y=ny;
res.l=tmp.l,res.r=tmp.r-1;
que.push(res);
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%d%d%d%d",&r,&c,&x,&y);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
cin>>s[i][j];
}
bfs();
printf("%d\n",ans);
return 0;
}