第一次小赛
A.Gym - 102152J 暴力map
题意:
给一个n*m的矩阵,每一行内的数字可以随意交换,矩阵的美丽值定义为\(a[i][j]=a[i-1][j]\)的对数。问矩阵调整后最大的美丽值。
n和m都是1e3的,矩阵内数值范围是1-1e8
做法:
用二维map维护,\(mp[i][j]\) 代表第 \(i\) 行有几个数字 \(j\) 。
最后两行之间共同拥有的数字的数量取min加到答案里。
闲话:
一开始还有点担心这复杂度,自从会用map之后,什么数组会爆掉的全用map一套解决,就是我不太会算时间复杂度和空间复杂度,听说map这两样都挺耗的,毕竟人家这么好用~
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const ll maxn=1e6+50;
namespace Fast_IO
{ //orz laofu
const int MAXL((1 << 18) + 1);int iof, iotp;
char ioif[MAXL], *ioiS, *ioiT, ioof[MAXL],*iooS=ioof,*iooT=ioof+MAXL-1,ioc,iost[55];
char Getchar(){
if (ioiS == ioiT){
ioiS=ioif;ioiT=ioiS+fread(ioif,1,MAXL,stdin);return (ioiS == ioiT ? EOF : *ioiS++);
}else return (*ioiS++);
}
void Write(){fwrite(ioof,1,iooS-ioof,stdout);iooS=ioof;}
void Putchar(char x){*iooS++ = x;if (iooS == iooT)Write();}
inline int read(){
int x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
if(ioc==EOF)exit(0);
for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
}
inline long long read_ll(){
long long x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
if(ioc==EOF)exit(0);
for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
}
template <class Int>void Print(Int x, char ch = '\0'){
if(!x)Putchar('0');if(x<0)Putchar('-'),x=-x;while(x)iost[++iotp]=x%10+'0',x/=10;
while(iotp)Putchar(iost[iotp--]);if (ch)Putchar(ch);
}
void Getstr(char *s, int &l){
for(ioc=Getchar();ioc==' '||ioc=='\n'||ioc=='\t';)ioc=Getchar();
if(ioc==EOF)exit(0);
for(l=0;!(ioc==' '||ioc=='\n'||ioc=='\t'||ioc==EOF);ioc=Getchar())s[l++]=ioc;s[l] = 0;
}
void Putstr(const char *s){for(int i=0,n=strlen(s);i<n;++i)Putchar(s[i]);}
} // namespace Fast_IO
using namespace Fast_IO;
ll a[1050][1050];
int main()
{
ll T;
T=read_ll();
while(T--)
{
map<ll,map<ll,ll> >mp;
ll n,m;
n=read_ll();
m=read_ll();
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=m;j++)
{
a[i][j]=read_ll();
mp[i][a[i][j]]++;
}
}
ll sum=0;
for(ll i=2;i<=n;i++)
{
for(auto &j:mp[i])
{
sum+=min(j.second,mp[i-1][j.first]);
}
}
printf("%lld\n",sum);
}
}
B.Gym - 102152C 找规律
题意:
给定n和m,定义\(F(n,m)=gcd(5^n+7^n,5^m+7^m)\)
求\(F(n,m)\),保证给定的n和m一定互质。
做法:
这是个规律题,首先分析,n和m不可能同为偶数。
当n和m同为奇数时,答案为12,
否则,答案为2。
闲话:
我活生生对着这题看了快一个小时你敢信,其实我中间有想到奇偶规律。我一开始就是觉得他是有规律的,所以写了个暴力程序跑,然后大概是n和m太大就炸掉了,所以蒙蔽了我的双眼,让我成功错过了正确答案,最后忍不住去看了题解。发现是我**了。感觉做题的一个规律就是,注意观察其他人的过题时间,运行时间以及内存来推算自己的做法,虽然现场赛好像是看不到这些的~
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const ll maxn=1e6+50;
namespace Fast_IO
{ //orz laofu
const int MAXL((1 << 18) + 1);int iof, iotp;
char ioif[MAXL], *ioiS, *ioiT, ioof[MAXL],*iooS=ioof,*iooT=ioof+MAXL-1,ioc,iost[55];
char Getchar(){
if (ioiS == ioiT){
ioiS=ioif;ioiT=ioiS+fread(ioif,1,MAXL,stdin);return (ioiS == ioiT ? EOF : *ioiS++);
}else return (*ioiS++);
}
void Write(){fwrite(ioof,1,iooS-ioof,stdout);iooS=ioof;}
void Putchar(char x){*iooS++ = x;if (iooS == iooT)Write();}
inline int read(){
int x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
if(ioc==EOF)exit(0);
for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
}
inline long long read_ll(){
long long x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
if(ioc==EOF)exit(0);
for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
}
template <class Int>void Print(Int x, char ch = '\0'){
if(!x)Putchar('0');if(x<0)Putchar('-'),x=-x;while(x)iost[++iotp]=x%10+'0',x/=10;
while(iotp)Putchar(iost[iotp--]);if (ch)Putchar(ch);
}
void Getstr(char *s, int &l){
for(ioc=Getchar();ioc==' '||ioc=='\n'||ioc=='\t';)ioc=Getchar();
if(ioc==EOF)exit(0);
for(l=0;!(ioc==' '||ioc=='\n'||ioc=='\t'||ioc==EOF);ioc=Getchar())s[l++]=ioc;s[l] = 0;
}
void Putstr(const char *s){for(int i=0,n=strlen(s);i<n;++i)Putchar(s[i]);}
} // namespace Fast_IO
using namespace Fast_IO;
ll a[1050][1050];
ll qpow(ll a,ll b)
{
ll ans=1;
ll base=a;
while(b)
{
if(b&1)ans=ans*base;
base*=base;
b>>=1;
}
return ans;
}
bool isPrime_3(int n)
{
if(n==2||n==3) return 1;
if(n%6!=1&&n%6!=5) return 0;
for(int i=5;i<=floor(sqrt(n));i+=6)
if(n%i==0||n%(i+2)==0) return 0;
return 1;
}
int main()
{
ll T;
T=read_ll();
while(T--)
{
ll n,m;
n=read_ll();
m=read_ll();
if(n%2&&m%2)printf("12\n");
else printf("2\n");
}
}
C.Gym - 102152I 分类讨论
题意:
有一个长度为n序列,定义取反操作为将某一个位置上的数变为它的相反数,n和k范围都是1e4,问进行k次取反操作后序列和的最大值,序列里的数字范围是 -1e4~1e4。
做法:
正宗分类讨论,但是你得心细。
首先统计一下序列里负数的个数fu。
把整个序列按从小到大排序。
1.如果fu>=k,则把最小的k个数取反,即把绝对值最大的一批负数取反以获得最大的收益。
2.如果fu<k,则说明对负数取反完后还会剩下一些取反操作,如果这些取反操作用在正数上则会导致最大值减小。
想到的解决办法是:
①如果序列里有0,则非常简单,把剩下的取反操作全部用在0上即可获得最大答案。
②如果序列里无0,则需把目前取反后的序列重新从小到大排序,取最小的元素,把剩下的所有取反次数都用在它身上。如果剩余次数为奇数,则最小的这个数会被取反(就算这样损失也是最小的),如果是偶数则不会发生改变。
其实①②这两种分类讨论可以合并成一个操作做,就先排序,再取出最小的,因为如果有0在的话,那0一定是最小的(因为在这个情况下,负数已经被全部取反了)。
闲话:
这道题我一开始太单纯了,纯粹地以为排个序,把前k个取反就好了,结果后来发现可以不停地取反同一个位置。负数当然是能取反多少就取反多少,正数则是能不取反就不取反,零可以用来消耗取反次数。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn=1e6+50;
namespace Fast_IO
{ //orz laofu
const int MAXL((1 << 18) + 1);int iof, iotp;
char ioif[MAXL], *ioiS, *ioiT, ioof[MAXL],*iooS=ioof,*iooT=ioof+MAXL-1,ioc,iost[55];
char Getchar(){
if (ioiS == ioiT){
ioiS=ioif;ioiT=ioiS+fread(ioif,1,MAXL,stdin);return (ioiS == ioiT ? EOF : *ioiS++);
}else return (*ioiS++);
}
void Write(){fwrite(ioof,1,iooS-ioof,stdout);iooS=ioof;}
void Putchar(char x){*iooS++ = x;if (iooS == iooT)Write();}
inline int read(){
int x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
if(ioc==EOF)exit(0);
for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
}
inline long long read_ll(){
long long x=0;for(iof=1,ioc=Getchar();(ioc<'0'||ioc>'9')&&ioc!=EOF;)iof=ioc=='-'?-1:1,ioc=Getchar();
if(ioc==EOF)exit(0);
for(x=0;ioc<='9'&&ioc>='0';ioc=Getchar())x=(x<<3)+(x<<1)+(ioc^48);return x*iof;
}
template <class Int>void Print(Int x, char ch = '\0'){
if(!x)Putchar('0');if(x<0)Putchar('-'),x=-x;while(x)iost[++iotp]=x%10+'0',x/=10;
while(iotp)Putchar(iost[iotp--]);if (ch)Putchar(ch);
}
void Getstr(char *s, int &l){
for(ioc=Getchar();ioc==' '||ioc=='\n'||ioc=='\t';)ioc=Getchar();
if(ioc==EOF)exit(0);
for(l=0;!(ioc==' '||ioc=='\n'||ioc=='\t'||ioc==EOF);ioc=Getchar())s[l++]=ioc;s[l] = 0;
}
void Putstr(const char *s){for(int i=0,n=strlen(s);i<n;++i)Putchar(s[i]);}
} // namespace Fast_IO
using namespace Fast_IO;
ll a[maxn];
int main()
{
ll T;
T=read_ll();
while(T--)
{
ll n,k,fu=0,ling=0,sum=0;
n=read_ll();
k=read_ll();
for(ll i=1;i<=n;i++){
a[i]=read_ll();
if(a[i]<0)fu++;
else if(a[i]==0)ling++;
}
sort(a+1,a+1+n);
if(fu<k)
if(ling)
for(ll i=1;i<=n;i++)
if(a[i]<0)sum+=-a[i];
else sum+=a[i];
else
{
for(ll i=1;i<=n;i++){
if(a[i]>=0)break;
a[i]=-a[i];
}
sort(a+1,a+1+n);
if((k-fu)%2)sum+=-a[1];
else sum+=a[1];
for(ll i=2;i<=n;i++)sum+=a[i];
}
else
for(ll i=1;i<=n;i++)
if(i<=k)sum+=-a[i];
else sum+=a[i];
printf("%lld\n",sum);
}
}
大大大闲话
虽然昨晚上第一场小赛我缺席了,但是今天我补上啦~,虽然还是菜菜的,但是看着一个队都是绿的真开心!冲冲冲!