A. 【2020男人八题】礼物
考场代码:(100pts)
#include<cstdio>
using namespace std;
long long Mod=1000000007;
int main()
{
long long n,m;
scanf("%lld%lld",&n,&m);
long long NN=n*(n-1)/2;
long long MM=m*(m-1)/2;
printf("%lld\n",((NN%Mod)*(MM%Mod)%Mod));
return 0;
}
这道题目考察 long long 的相关问题,注意随时取模就好了,考场上找规律大概 才写好。算是挺签到的题目。
B. 【2020男人八题】序列
考场代码:(40pts)
#include<cstdio>
using namespace std;
long long a[100005],b[100005],c[100005];
long long Abs(long long x)
{
if(x<0)return -x;
return x;
}
int main()
{
long long n,S;
long long sum=0;
long long dif=0;
scanf("%lld%lld",&n,&S);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum+=a[i];
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&b[i]);
}
if(sum<S)
{
printf("-1\n");
return 0;
}
long long cnt=0;
for(int i=1;i<=n;i++)
{
if(b[i]<=a[i])
{
c[i]=b[i];
}
else
{
c[i]=a[i];
dif+=Abs(c[i]-b[i]);
}
cnt+=c[i];
}
if(cnt==S)
{
printf("%lld\n",dif);
for(int i=1;i<=n;i++)
{
printf("%lld ",c[i]);
}
printf("\n");
return 0;
}
dif=0;
if(cnt<S)
for(int i=1;i<=n;i++)
{
long long tmp=a[i]-c[i];
if(c[i]<a[i])
{
if(S-cnt>tmp)
{
c[i]=a[i];
dif+=Abs(c[i]-b[i]);
cnt+=tmp;
}
else
{
c[i]+=S-cnt;
dif+=Abs(c[i]-b[i]);
cnt=S;
}
}
if(cnt==S)
{
printf("%lld\n",dif);
for(int i=1;i<=n;i++)
{
printf("%lld ",c[i]);
}
printf("\n");
return 0;
}
}
dif=0;
for(int i=1;i<=n;i++)
{
int tmp=c[i];
if(c[i]<a[i])
{
if(cnt-S>tmp)
{
c[i]=0;
dif+=Abs(c[i]-b[i]);
cnt-=tmp;
}
else
{
c[i]-=cnt-S;
dif+=Abs(c[i]-b[i]);
cnt=S;
}
}
if(cnt==S)
{
printf("%lld\n",dif);
for(int i=1;i<=n;i++)
{
printf("%lld ",c[i]);
}
printf("\n");
return 0;
}
}
printf("-1\n");
return 0;
}
赛后订正:(100pts)
#include<cstdio>
using namespace std;
long long a[100005],b[100005],c[100005];
long long abs(long long x)
{
if(x<0)return -x;
return x;
}
int main()
{
long long n,S;
scanf("%lld%lld",&n,&S);
long long sum=0;
for(long long i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum+=a[i];
}
long long cnt=0;
for(long long i=1;i<=n;i++)
{
scanf("%lld",&b[i]);
if(b[i]>a[i])
{
c[i]=a[i];
}
else
c[i]=b[i];
cnt+=c[i];
}
if(sum<S)
{
printf("-1\n");
return 0;
}
long long flag=0;
for(long long i=1;i<=n;i++)
{
long long del;
if(cnt>S)
{
del=cnt-S;
if(del<c[i])
{
c[i]=c[i]-del;
flag=1;
break;
}
else
{
cnt-=c[i];
c[i]=0;
}
}
if(cnt<S)
{
del=S-cnt;
if(del<a[i]-c[i])
{
c[i]+=del;
flag=1;
break;
}
else
{
cnt+=a[i]-c[i];
c[i]=a[i];
}
}
if(cnt==S)
{
flag=1;
break;
}
}
if(flag==0)
{
printf("-1\n");
return 0;
}
long long res=0;
for(long long i=1;i<=n;i++)
{
res+=abs(c[i]-b[i]);
}
printf("%lld\n",res);
for(long long i=1;i<=n;i++)
{
printf("%lld ",c[i]);
}
printf("\n");
return 0;
}
考场上对于两种分情况的讨论头脑有些混沌了,导致犯了一些本不该犯的错误。
以后还是应该一边写一边在旁边注释一下,理清思路。
原来的时候在初始化 c 数组之后,修正的过程中直接计算答案了,就会导致一些本可以避免的错误。
这种答案的统计因为时间复杂度不高,所以类似的题目处理时最好最后统一搞。
C. 【2020男人八题】洪水
赛时代码:(0pts)
#include<cstdio>
#include<algorithm>
using namespace std;
struct ben
{
long long x,y;
}a[10005];
long long cmp(const ben &a,const ben &b)
{
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
long long Abs(long long qaq)
{
if(qaq<0)return -qaq;
return qaq;
}
long long Max(long long qwq,long long qvq)
{
if(qwq>qvq)return qwq;
return qvq;
}
long long Min(long long qwq,long long qvq)
{
if(qwq<qvq)return qwq;
return qvq;
}
long long x[10005],y[10005];
int main()
{
long long W,H,n;
scanf("%lld%lld%lld",&W,&H,&n);
for(long long i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
}
//sort(a+1,a+n+1,cmp);
long long ans=0;
for(long long i=1;i<=n;i++)
{
long long tmp=2147483640000000;
for(long long j=1;j<=n;j++)
{
if(i==j)continue;
long long midx=(a[i].x+a[j].x)/2;
long long midy=(a[i].y+a[j].y)/2;
tmp=Min(tmp,Abs(midx-Min(a[i].x,a[j].x))+Abs(midy-Min(a[i].y,a[j].y)));
//prlong longf("tmp=%d\n",tmp);
//tmp=Min(tmp,zc);
//prlong longf("zc=%d\n",zc);
}
//prlong longf("tmp=%d\n",tmp);
if(tmp==2147483640000000)continue;//差点这句话就把等于写成了赋值。。。。。
ans=Max(ans,tmp);
}
printf("%lld\n",ans);
return 0;
}
赛后订正:(10pts)
#include<cstdio>
#include<algorithm>
using namespace std;
struct ben
{
int x,y;
}a[10005];
struct qwq
{
int ls,g;
}d[10005];
int mp[10005];
int Abs(int x)
{
if(x<0)return -x;
return x;
}
int ba[10005];
int main()
{
int W,H,n;
scanf("%d%d%d",&W,&H,&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
d[i].g=0;
}
for(int i=1;i<=n;i++)
{
if(d[i].g!=0)continue;
int tmp=2147483640,tag;
for(int j=i+1;j<=n;j++)
{
if((Abs(a[j].x-a[i].x)+Abs(a[j].y-a[i].y))/2<tmp)
{
tmp=(Abs(a[j].x-a[i].x)+Abs(a[j].y-a[i].y))/2;
tag=j;
}
}
d[i].ls=tmp;
d[i].g=tag;
d[tag].ls=tmp;
d[tag].g=i;
}
ba[1]=1;
int cnt=1;
mp[1]=1;
int ans=0;
while(cnt<n)
{
int mina=2147483640;
int taga;
for(int i=1;i<=cnt;i++)
{
if(d[ba[i]].ls<mina)
{
if(mp[d[ba[i]].g]==1)continue;
mina=d[ba[i]].ls;
taga=d[ba[i]].g;
}
}
mp[taga]=1;
ba[++cnt]=taga;
if(mina!=2147483640)
ans=max(ans,mina);
}
printf("%d\n",ans);
return 0;
}
考场上几乎把所有的错误想法都想过了一遍,最终摸索每一种错解之后走到了类似最小生成树的做法,但因打开方式不对,曼哈顿距离处理挂了
这道题目不能直接贪心,要用最小生成树的思想连边。赛时想到了类似的想法,但在曼哈顿距离上处理挂了。
D、 【2020男人八题】循环
赛时代码:(3pts)
#include<cstdio>
using namespace std;
int Mod=998244353;
long long a[21];
int main()
{
long long p;
scanf("%lld",&p);
int n=10;
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
if(p==3)
{
long long tmp=a[3]+a[6];
printf("%lld\n",tmp%Mod);
}
return 0;
}
赛后订正:(100pts)
#include<cstdio>
using namespace std;
int mod=998244353;
long long a[15];
bool tag[1000005];
long long xs[1000005];
int main()
{
long long n,cnt=0,ans=0,x;
scanf("%lld",&n);
for(int i=0;i<=9;i++)
{
scanf("%lld",&a[i]);
}
for(int i=1;i<n;i++)
{
if(tag[i]==0)
{
int tmp=0;
cnt++;
x=i;
xs[cnt]=1;
while(1)
{
tag[x]=1;
tmp++;
xs[cnt]=xs[cnt]*a[x*10/n]%mod;
x=x*10%n;
if(x==i)
break;
}
xs[cnt]=xs[cnt]*tmp%mod;
ans=(ans+xs[cnt])%mod;
}
}
printf("%lld\n",ans);
return 0;
}
赛时只考虑了样例的情况,因为没有琢磨透循环节所以只草率的写了极少的部分分。其实即使是骗分的暴力也还是很可做,本应多骗些分。
E. 【2020男人八题】切割矩形
赛时代码:(30pts)
#include<cstdio>
#include<iostream>
using namespace std;
long long Max(long long qwq,long long qvq)
{
if(qwq>qvq)return qwq;
return qvq;
}
int main()
{
int T;
scanf("%d",&T);
long long a,b;
while(T--)
{
scanf("%lld%lld",&a,&b);
long long x1=a,x2=b,y1=b,y2=b;
long long ans=0;
while(x1!=y1)
{
if(x1>y1)
{
long long tmp=x1-(x1/y1)*y1;
if(tmp<1)
{
ans-=(1-tmp)/y1;
}
ans+=x1/y1;
x1=Max(tmp,1);
}
else
{
long long z=x1;
x1=y1;
y1=z;
}
//printf("%lld %lld\n",x1,y1);
}
printf("%lld 114514\n",ans);
}
return 0;
}
赛后订正:(100pts)
#include<cstdio>
using namespace std;
int mod=1000000007;
long long res1,res2;
long long ksm(long long a,long long b)
{
long long tmp=1;
for(;b;b/=2,a=a*a%mod)
{
if(b%2==1)
{
tmp=tmp*a%mod;
}
}
return tmp;
}
void gcd_ex(long long a,long long b)
{
if(b==1)
{
res1=a-1;
res2=0;
return ;
}
gcd_ex(b,a%b);
res2=(ksm(2,res1)-res2-1+mod)%mod;
res1+=a/b;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
long long a,b;
scanf("%lld%lld",&a,&b);
gcd_ex(a,b);
printf("%lld %lld\n",res1,(ksm(2,res1-1)-res2+mod)%mod);
}
return 0;
}
这道题在比赛时写了第一个空的解法,看出其和辗转相除法相似的本质,得到了30pts,对整场比赛的个人得分来说算是比较成功的暴力,但没有像初中探究题一样推下去找到第二问的规律比较可惜。