1. 程式人生 > 實用技巧 >第一次小賽

第一次小賽

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);
	}
}

大大大閒話

雖然昨晚上第一場小賽我缺席了,但是今天我補上啦~,雖然還是菜菜的,但是看著一個隊都是綠的真開心!沖沖衝!