「考试」大假期集训模拟10

反思

  • 暴力一定要打,T2 (O(n^6))有70分,加上二维前缀和就将近(A)掉了,可能有时候并不知道最优解,但是一定要把能拿到的分拿到

简述

T1

一道dp,设(f[i][j])(s1,s2)分别到(i.j)位时最小距离,状态转移方程易得:

[f[i][j]=min(f[i-1][j]+k,f[i][j-1]+k,f[i-1][j-1]+dif(i,j)) ]

T2

解锁了二维哈希新姿势
会的话就是板子了……



#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define ZZ_zuozhe int main()
#define N 105

ull n;
ull a[N][N],b[N][N];
const ull base1=11,base2=13;
ull p1[N],p2[N];
void pp()
{
	p1[0]=p2[0]=1;
	for(int i=1;i<=n;i++)p1[i]=p1[i-1]*base1;
	for(int i=1;i<=n;i++)p2[i]=p2[i-1]*base2;
}

ull get(ull aa[][N],ll x,ll y,ll h)
{
	return aa[x][y]-aa[x-h][y]*p2[h]-aa[x][y-h]*p1[h]+aa[x-h][y-h]*p1[h]*p2[h];
}

map<ull,bool>mp;

ZZ_zuozhe
{
	scanf("%lld",&n);
	pp();
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%lld",&a[i][j]);
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%lld",&b[i][j]);
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)a[i][j]=a[i][j-1]*base1+a[i][j];
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)a[i][j]=a[i-1][j]*base2+a[i][j];
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)b[i][j]=b[i][j-1]*base1+b[i][j];
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)b[i][j]=b[i-1][j]*base2+b[i][j];
	for(int k=0;k<=n;k++)for(int i=k;i<=n;i++)for(int j=k;j<=n;j++)mp[get(a,i,j,k)]=1;
	for(int k=n;k>=0;k--)for(int i=k;i<=n;i++)for(int j=k;j<=n;j++)if(mp.find(get(b,i,j,k))!=mp.end()){printf("%d",k);return 0;}
	return 0;
}

刚开始想的是二维前缀和,然后转到二维哈希发现并不会写……
其实二维前缀和+暴力比较似乎直接能(A)掉?所以以后暴力分一定要打……

T3

一个结论:对于一个数,把他分解质因数,得到(A=p_1^{a_1}cdot p_2^{a_2}cdot dots cdot p_n^{a_n})
则这个数约数总数为((a_1+1)cdot (a_2+1)cdot dots cdot (a_n+1))
所以可以用一个dfs搜索答案
注意:如果质因数指数和相同的情况下,为了使他更小,应当尽量使用更小的质因数,可以发现质因数的指数应该是单调不增的。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
ll n,ans=-1,maxn=-1;

const ll p[20]={1,2,3,5,7,11,13,17,19,23,29,31};

void dfs(ll now,ll cnt,ll t,ll po)
{
	if(t>maxn||(t==maxn&&now<ans))
	{
		ans=now;
		maxn=t;
	}
	ll tmp=now;
	for(int i=1;i<=po;i++)
	{
		if(tmp*p[cnt]>n)break;
		tmp*=p[cnt];
		if(tmp<=n)dfs(tmp,cnt+1,t*(i+1),i);
	}
}

int main()
{
	scanf("%lld",&n);
	dfs(1,1,1,30);
	printf("%lld",ans);
	return 0;
}

T4

一道贪心好题
需要注意的是看出贪心的过程:如果当前必须把一个玩具放上去,如果这个玩具马上就要用了,还要把它拿下来,再把另外一个放上去……会造成很多不必要的麻烦
所以,每次需要把玩具放上去时,应当找一个再拿下来时间最晚的玩具放上去,尽量减少其对其他玩具的影响。
这里用到了(priority_queue)(pair)(STL)我一直都不很熟……以后得多看看,因为有时候它是真的方便……

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define ZZ_zuozhe int main()
#define N 500005

ll n,k,p,now,ans=0;
ll a[N],last[N],next[N];
bool vis[N];
priority_queue<pair<ll,ll> > Q;
pair<ll,ll> pt;

int main()
{
	scanf("%lld%lld%lld",&n,&k,&p);
	for(int i=1;i<=p;i++)scanf("%lld",&a[i]);
	for(int i=1;i<=p;i++)last[a[i]]=p+1;
	for(int i=p;i>=1;i--)next[i]=last[a[i]],last[a[i]]=i;
	
	for(int i=1;i<=p;i++)
	{
		if(vis[a[i]])
		{
			k++;
			Q.push(make_pair(next[i],a[i]));
		}
		else 
		{
			if(!Q.empty()&&Q.size()==k)
			{
				pt=Q.top();
				Q.pop();
				vis[pt.second]=0;
			}
			ans++;
			Q.push(make_pair(next[i],a[i]));
			vis[a[i]]=1;
		}
	}
	printf("%lld",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/zzzuozhe-gjy/p/13413172.html