模拟赛二补题报告
李智航S13494
这里写自定义目录标题
前言
·下棋(chess)
·汪洋(BigWater)
·删数(delnum)
·平分糖果(candy)
一.题目报告
比赛中,第一题AC,第二题与第四题都爆了(运行错误),第二题5分,第四题35分,第三题直接爆0;
二.赛中概况
第一题那个数据范围是真的恶心,需要开long long,第二题wa一堆,第三题没时间,直接打了一个自己都不知道的东西,第四题吧范围看错了,少打了一个0,痛失65分。
三.解题报告
1.下棋(chess)
1.题目描述:
2.开始代码如下:
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define ll long long
struct S{
ll x,y,z;//z为一星,y为两星,x为三星
ll all;
ll num;
}a[100001];
bool cmp(S a1,S b1){
if(a1.all==b1.all){
return a1.num<b1.num;
}
return a1.all>b1.all;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].z>>a[i].y>>a[i].x;
a[i].num=i;
}
for(int i=1;i<=n;i++){
int zz=a[i].z/3;
a[i].z%=3;
a[i].y+=zz;
int yy=a[i].y/3;
a[i].y%=3;
a[i].x+=yy;
}
for(int i=1;i<=n;i++){
a[i].all=18*a[i].x+3*a[i].y+a[i].z;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
cout<<a[i].num<<" ";
}
return 0;
}
思路:直接暴力,通过题目可得18x+3y+z,3个换一个更高级的,3z换y,所以z和y换不换一样,但是3y=x,但一个x的价值是18.两个价值相差很大。所以直接转换就行,不需要考虑不换的情况。
3.正解
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
struct player{
long long x,y,z,sum;
int num;
}a[100005];
bool cmp(player a,player b){
if(a.sum!=b.sum) return a.sum>b.sum;
else return a.num<b.num;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld %lld %lld",&a[i].z,&a[i].y,&a[i].x);
a[i].y+=a[i].z/3;
a[i].z%=3;
a[i].x+=a[i].y/3;
a[i].y%=3;
a[i].sum=a[i].x *18+a[i].y*3+a[i].z;
a[i].num=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++) printf("%d ",a[i].num);
return 0;
}
2.汪洋(BigWater)
1.题目:
2.开始题目代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 205;
int n;
int a[N][N];
bool v[N][N];
// 方向数组:右、下、左、上
int dx[]= {0,1,0,-1};
int dy[]= {1,0,-1,0};
void dfs(int x,int y,int fx,int m,int &mm) {
mm=max(mm,m);
int nx=x+dx[fx];
int ny=y+dy[fx];
if(nx>=0&&nx<n&&ny>=0&&ny<n&&!v[nx][ny]) {
v[nx][ny]=true;
dfs(nx,ny,fx,m+a[nx][ny],mm);
v[nx][ny]=false;
}
int nfx=(fx+1)%4;
nx=x+dx[nfx];
ny=y+dy[nfx];
if (nx>=0&&nx<n&&ny>=0&&ny<n&&!v[nx][ny]) {
v[nx][ny]=true;
dfs(nx,ny,nfx,m+a[nx][ny],mm);
v[nx][ny]=false;
}
}
int main() {
cin>>n;
for(int i=0; i<n; i++) {
for(int j=0; j<n; j++) {
cin>>a[i][j];
}
}
v[0][0]=true;
int mm=100;
dfs(0,0,0,100,mm);
cout<<mm<<endl;
return 0;
}
思路:
(直接交给电脑),就是一直往下找,把所有地点遍历一遍,但忘了覆盖之前的答案。
只能顺时针转弯,,所以就是一直走和转弯两种情况递归。
3.正解:
#include<bits/stdc++.h>
using namespace std;
long long n,r[1001][1001],c[1001][1001],a[1001][1001],ans=-1145141;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
r[i][j]=r[i][j-1]+a[i][j];
c[i][j]=c[i-1][j]+a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans=max(ans,r[i][j]+r[1][j]+c[i][j]+c[i][1]-a[1][1]-a[1][j]-a[i][1]-a[i][j]);
}
}
cout<<ans+100;
return 0;
}
3.删数(delnum)
1.题目:
2.开始代码:
#include<bits/stdc++.h>
using namespace std;
int a[100001];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int ans;
cin>>ans;
for(int i=1;i<=ans;i++){
int x;
cin>>x;
cout<<x/5-1<<endl;
}
return 0;
}
直接靠运气,没有任何思路,推了推样例,第一个除了5,整除,第二个答案60%是除以5在减1,所以就试了试,直接崩了。
3.正解
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,del[100005];
int q,x;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&del[i]);
scanf("%d",&q);
while(q--){
scanf("%d",&x);
int cnt=0,f=0;
for(int i=n;i>=1;i--){
if(del[i]<=x){
cnt+=(x-del[i])/i;
x=del[i]+(x-del[i])%i;
if(del[i]<x){
cnt++;
x-=i;
}
if(x==del[i]){
f=1;
break;
}
}
}
if(f) printf("%d\n",cnt+1);
else printf("0\n");
}
return 0;
}
就是从前往后推,删除前N小的数字,直到删了那个数字,从后往前删。
4.平分糖果(candy)
1.题目:
2.开始代码:
#include<bits/stdc++.h>
using namespace std;
int c;//记录局数
int d[200005];
#define endl "\n"
int main() {
int a[6];
while (true) {
cin>>a[0]>>a[1]>>a[2]>>a[3]>>a[4]>>a[5];
if (a[0]==0&&a[1]==0&&a[2]==0&&a[3]==0&&a[4]==0&&a[5]==0) {//stop
break;
}
c++;
int t=0;//总美味程度
for (int i=0;i<6;++i) {
t+=a[i]*(i+1);//i+1为当前甜度
}
// 如果总和为奇数,直接输出 Can't be divided.
if (t%2!=0) {
cout<<"Collection #"<<c<<":"<<endl<<"Can't be divided."<<endl;
cout<<endl;
continue;
}
//总和为偶数
else{
int ta=t/2;
// vector<bool> d(ta+1,false);
d[0]=true; //0美可以通过不选任何糖果获得
for (int i=0;i<6;++i){
if (a[i]>0){
for (int j=ta;j>=(i+1);--j){
for (int k=1;k<=a[i]&&k*(i+1)<=j;++k){//k为个数
if(d[j-k*(i+1)]){
d[j]=true;
}
}
}
}
}
if(d[ta]) {
cout<<"Collection #"<<c<<":"<<endl<<"Can be divided."<<endl;
}
else{
cout<<"Collection #"<<c<< ":"<<endl<<"Can't be divided."<<endl;
}
cout<<endl;
}
}
return 0;
}
思路:因为是平分,所以奇数个数的糖果一定不能平分,直接过掉。
剩下的情况就是偶数的情况:
以t为一半分,算出两边相同的甜度相同的值ta。
用d数组判断可不可以匹配。如果一直匹配到ta一直为true的话,那么就成立
中间的那个循环就是在平分两边的甜度
3.正解:
#include<bits/stdc++.h>
using namespace std;
long long a[7],m,dp[7][100001],cnt;
int main(){
while(1){
m=0;
for(int i=1;i<=6;i++){
cin>>a[i];
m+=a[i]*i;
}
if(!m) break;
cout<<"Collection #"<<++cnt<<":"<<endl;
dp[0][0]=1;
for(int i=1;i<=6;i++){
for(int j=0;j<=a[i];j++){
for(int k=j*i;k<=m/2;k++){
dp[i][k]|=dp[i-1][k-j*i];
}
}
}
if(m%2==0&&dp[6][m/2]==1){
cout<<"Can be divided."<<endl<<endl;
}
else{
cout<<"Can't be divided."<<endl<<endl;
}
}
return 0;
}
总结:
时间上还是有点问题,有些地方还是想不到小的细节,数据范围出了问题,少开了一位数,直接分数就下来了.