1. 程式人生 > 實用技巧 >「考試」大假期集訓模擬16

「考試」大假期集訓模擬16

反思

  • 第二遍了,一定要看資料範圍……

題目簡述

T1 老光棍

可以\(hash\)一波帶走,複雜度是\(O(Tn)\)
注意:多解的情況是“不同的字串\(A\)”,所以在增加答案的時候需要特別判斷其和原來的答案是否相同
code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define N 2000005

ll T,n;
char s[N];
bool vis[30],flag;
ll ans=0,pos;

const ull base=31;
ull hash[N],po[N];
void pp()
{
	po[0]=1;
	for(int i=1;i<=N;i++)po[i]=po[i-1]*base;
}
void gethash()
{
	memset(hash,0,sizeof hash);
	hash[0]=0;
	for(int i=1;i<=n;i++)
	{
		hash[i]=hash[i-1]*base+(s[i]-'A');
	}
}
ull get(ll l,ll r)
{
	if(l>r)return 0;
	return hash[r]-hash[l-1]*po[r-l+1];
}
ull tmp;

int main()
{
	//freopen("owo.in","r",stdin);
	scanf("%lld",&T);
	pp();
	while(T--)
	{
		scanf("%lld",&n);
		scanf("%s",s+1);
		if(n%2==0)
		{
			puts("NOT POSSIBLE");
			continue;
		}
		gethash();
		ll t=(n+1)/2;
		ans=0;
		tmp=-1;
		//cout<<endl;
		for(int i=1;i<=t;i++)
		{
			//cout<<1<<' '<<i-1<<' '<<i+1<<' '<<t<<' '<<t+1<<' '<<t+i-1<<' '<<t+i<<' '<<n<<endl;
			//cout<<get(1,i-1)<<' '<<get(t+1,t+i-1)<<' '<<get(i+1,t)<<' '<<get(t+i,n)<<endl;
			if(get(1,i-1)==get(t+1,t+i-1)&&get(i+1,t)==get(t+i,n))
			{	
				if(get(t+1,n)!=tmp)ans++;
				tmp=get(t+1,n);
				pos=i;
				//cout<<pos<<endl;
			}
		}
		for(int i=t+1;i<=n;i++)
		{
			//cout<<get(1,i-t)<<' '<<get(t,i-1)<<' '<<get(i-t+1,t-1)<<' '<<get(i+1,n)<<endl;
			if(get(1,i-t)==get(t,i-1)&&get(i-t+1,t-1)==get(i+1,n))
			{
				if(get(1,t-1)!=tmp)ans++;
				tmp=get(1,t-1);
				pos=i;
				//cout<<pos<<endl;
			}
		}
		if(ans>1)
		{
			puts("NOT UNIQUE");
		}
		else if(ans==0)
		{
			puts("NOT POSSIBLE");
		}
		else 
		{
			if(pos<=t)
			{
				for(int i=t+1;i<=n;i++)putchar(s[i]);
			}
			else
			{
				for(int i=1;i<=t-1;i++)putchar(s[i]);
			}
			puts("");
		}
	}
	return 0;
}

T2 漁船

網路流?三分?在補了在補了……
(然而還並不知道網路流為何物
(可能不久會放上來……

T3 馬克的達人秀

原題luoguP4377 Talent Show
01分數規劃:洛穀日報\(#121\)
01分數規劃+01揹包\(\rightarrow\)最優比率揹包
code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define N 255
#define T 250005

ll n,ww;
ll t[N],w[N];
ll sum=0;
ll f[T];

bool work(ll x)
{
	memset(f,128,sizeof f);
	f[0]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=ww;j>=0;j--)
		{
			f[min(j+w[i],ww)]=max(f[min(j+w[i],ww)],f[j]+t[i]-x*w[i]);
		}
	}
	return f[ww]>=0;
}

int main()
{
	//freopen("owo.in","r",stdin);
	//freopen("awa.out","w",stdout);
	scanf("%lld%lld",&n,&ww);
	for(int i=1;i<=n;i++)scanf("%lld%lld",&w[i],&t[i]),t[i]*=1000;
	ll l=0,r=10000000,m;
	while(l<r)
	{
		m=(l+r)>>1;
		//cout<<m<<endl;
		if(work(m))l=m+1;
		else r=m;
	}
	printf("%lld",l-1);
	return 0;
}

T4 爬山

一個比較有用的結論:

給定一組資料,用猜來的平均值計算他的方差,計算結果一定\(\geq\)正確結果

推柿子:(by yspm
(設資料\(x_1\dots x_n\)已經給定,猜的平均數為\(\bar{x}\),為了方便,所有的\(\sum\limits^{n}_{i=1}\)簡寫為\(\sum\)

\[\begin{aligned} s^2&=\frac{\sum(x_i-\bar{x})^2}{n}\\ &=\frac{\sum(x_i^2)-2\sum(x_i\bar{x})+\sum(\bar{x}^2)}{n}\\ \frac{\sum(x_i^2)}{n}是定值,去掉\\ &=\frac{\sum(\bar{x}^2)-2\sum(x_i\bar{x})}{n}\\ &=\bar{x}^2-\frac{2\sum(x_i\bar{x})}{n}\\ &=\bar{x}^2-\frac{2\bar{x}\sum x_i}{n}\\ 配方得\\ &=(\bar{x}-\frac{\sum x_i}{n})^2-(\frac{\sum x_i}{n})^2\\ 當且僅當取\bar{x}=\frac{\sum x_i}{n}時,取最小值\\ 其中\frac{\sum x_i}{n}即為正確的平均數\\ \end{aligned}\]

所以,可以列舉每個點到終點的路徑長度與經過的點數,從而得到這條路徑的平均值,用這個“猜到”的平均值計算到終點的最小方差,取所有這些答案裡的最小值就是正確答案
另外有向無環圖可以用拓撲排序幫助求最短路
code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define db double
#define E 2005
#define N 55
#define inf 10000000000000000

struct edge
{
	ll u,v,w;
}e[E];
ll head[E],next[E],tot=0;
void add(ll a,ll b,ll c)
{
	++tot;
	e[tot].u=a;
	e[tot].v=b;
	e[tot].w=c;
	next[tot]=head[a];
	head[a]=tot;
}

ll n,m,a,b,c;
ll in[N],tmp[N];
double ans=1e16;
queue<ll> q;
ll mi[N][25],mx[N][25];
db dis[N][25];

int main()
{
	//freopen("owo.in","r",stdin);
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld%lld",&a,&b,&c);
		add(a,b,c);
		in[b]++;
	}
	while(!q.empty())q.pop();
	memcpy(tmp,in,sizeof in);
	for(int i=1;i<=n;i++)if(!tmp[i])q.push(i);
	for(int i=1;i<=n;i++)for(int j=0;j<=20;j++)mi[i][j]=inf,mx[i][j]=-inf;
	mi[1][0]=mx[1][0]=0;
	while(!q.empty())
	{
		ll u=q.front();
		//cout<<u<<endl;
		q.pop();
		for(int i=head[u];i;i=next[i])
		{
			ll v=e[i].v;
			for(int j=0;j<=19;j++)
			{
				if(mi[u][j]!=inf)
				{
					mi[v][j+1]=min(mi[v][j+1],mi[u][j]+e[i].w);
					mx[v][j+1]=max(mx[v][j+1],mx[u][j]+e[i].w);
					//cout<<mi[v][j+1]<<' '<<mx[v][j+1]<<endl;
				}
			}
		}
		for(int i=head[u];i;i=next[i])
		{
			ll v=e[i].v;
			if(--tmp[v]==0)q.push(v);
		}
	}
	for(int i=1;i<=19;i++)
	{
		//cout<<mi[n][i]<<endl;
		if(mi[n][i]==inf)continue;
		for(int j=mi[n][i];j<=mx[n][i];j++)
		{
			db avg=(db)j/(db)i;
			//cout<<avg<<endl;
			memcpy(tmp,in,sizeof in);
			for(int k=1;k<=n;k++)for(int l=0;l<=19;l++)dis[k][l]=inf;
			dis[1][0]=0;
			while(!q.empty())q.pop();
			for(int k=1;k<=n;k++)if(!tmp[k])q.push(k);
			while(!q.empty())
			{
				ll u=q.front();
				q.pop();
				//cout<<u<<endl;
				for(int k=0;k<i;k++)
				{
					if(dis[u][k]==inf)continue;
					for(int l=head[u];l;l=next[l])
					{
						ll v=e[l].v,w=e[l].w;
						dis[v][k+1]=min(dis[v][k+1],dis[u][k]+((db)w-avg)*((db)w-avg));
					}
				}
				for(int k=head[u];k;k=next[k])
				{
					ll v=e[k].v;
					if(--tmp[v]==0)q.push(v);
				}
			}
			//cout<<dis[n][i]<<endl;
			ans=min(ans,dis[n][i]/(db)i);
		}
	}
	printf("%.4lf",ans);
	return 0;
}