第一次小賽
A.暴力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.找規律
題意:
給定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.分類討論
題意:
有一個長度為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);
}
}
大大大閒話
雖然昨晚上第一場小賽我缺席了,但是今天我補上啦~,雖然還是菜菜的,但是看著一個隊都是綠的真開心!沖沖衝!