2021 10.9 模拟测试 *

image

T1

容易想到转移方程,去枚举\(k\),\(sum[i]=min(sum[i],sum[i-j]+cost[k])\)
如果我们可以\(O(1)\)得找到每个\(k\)对应的\(j\),那么就可以\(O(NK)\)的过了。发现\(T\)是有单调性的,所以我们对\(cost\)\(num\)排个序,再记一个指针,每回跳的时候把最终位置记下来,到下一个\(k\)的时候从这个位置回跳就可以了。

#include<bits/stdc++.h>
#define int long long
#define in read()
using namespace std;
inline int read()
{
    int data=0,w=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
const int N=1e5+10;
struct node{
	int num,cost;
}p[N];
int n,k,w;
int t[N],sum[N];
bool cmp(node a,node b)
{
	if(a.num==b.num) return a.cost<b.cost;
	return a.num<b.num;
}
signed main()
{
	#ifdef socc
	freopen("soc.in","r",stdin);
	#else
	//freopen("buy.in","r",stdin);
	//freopen("buy.out","w",stdout);
	#endif
	n=in,k=in;
	for(int i=1;i<=n;i++) t[i]=in;
	for(int i=1;i<=k;i++) p[i].num=in,p[i].cost=in;
	w=in;
	if(k==0) {for(int i=1;i<=n;i++) write(w),puts("");return 0;}
	sort(p+1,p+k+1,cmp);
	sum[1]=w;write(w),puts("");
	for(int i=2;i<=n;i++)
	{
		int flag=i;
		sum[i]=sum[i-1]+w;
		for(int j=1;j<=k;j++)
		{
			if(p[j-1].num==p[j].num) continue;
			int x=t[i]-p[j].num+1;
			if(x<=0)
			{
				sum[i]=min(sum[i],p[j].cost);
				break;
			}
			while(t[flag]>=x) flag--;
			sum[i]=min(sum[i],sum[flag]+p[j].cost);
		}
		write(sum[i]-sum[i-1]),puts("");
	}
}

T2

\(g_i\) 表示与全满状态相差 \(i\) 根木棒至少需要多少根木棒,我们有:

\[g_i=\displaystyle\min_{j=1}^Nj+g_{i-j\times(j-1)/2} \]

这样总 \(dp\) 的复杂度就是 \(O(N^3)\) 的了。考虑一组询问 \((N, M)\),他能完成当且仅当\(g_{N×(N−1)/2−M} ≤ N\)。总复杂度为 O(N3 + M)。

#include<bits/stdc++.h>
using namespace std;
#define in read()
inline int read(){
	int p=0,f=1;
	char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
	return p*f;
}
const int M=2e5+5;
int T,g[M],n[M],m[M],maxn;
signed main(){
	T=in;	
	for(int i=1;i<=T;i++)
		n[i]=in,m[i]=in,maxn=max(maxn,n[i]);
	memset(g,127,sizeof(g));g[0]=0;
	for(int i=0;i<=maxn*(maxn-1)/2;i++)
		for(int j=1;j<=maxn&&i+j*(j-1)/2<=maxn*(maxn-1)/2;j++)
			g[i+j*(j-1)/2]=min(g[i]+j,g[i+j*(j-1)/2]);
	for(int i=1;i<=T;i++)
		cout<<(m[i]<=n[i]*(n[i]-1)/2&&(g[n[i]*(n[i]-1)/2-m[i]]<=n[i]))<<'\n';
	return 0;
}

当然不弄\(dp\)枚举状态也可以过,\(bool\)\(500\times125000\)是没有问题的

#include<bits/stdc++.h>
#define pb push_back
#define in read()
using namespace std;
inline int read()
{
    int data=0,w=1; char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return data*w;
}
inline void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
const int N=505;
const int M=124800;
int Q,n,m,c[N],len[N];
bool cnt[N][M];
vector<int> a[N];
void pre()
{
	for(int i=1;i<=500;i++)
	{
		c[i]=(i*(i-1))>>1;
		memcpy(cnt[i],cnt[i-1],sizeof(cnt[i-1]));
		a[i]=a[i-1];len[i]=len[i-1];
		for(int j=0,k=1;j<len[i-1];++j)
		{
			if(j>=len[k]) k++;
			if(cnt[i][a[k][j]+c[i-k]]) continue;
			cnt[i][a[k][j]+c[i-k]]=1;
			a[i].pb(a[k][j]+c[i-k]);
			len[i]++;
		}
		cnt[i][c[i]]=1;
		a[i].pb(c[i]);len[i]++;
	}
} 
int main()
{
	#ifdef socc
	//freopen("soc.in","r",stdin);
	#else
	//freopen("intersect.in","r",stdin);
	//freopen("intersect.out","w",stdout);
	#endif
	pre();
	Q=in;
	while(Q--)
	{
		n=in,m=in;
		if(c[n]<m) puts("0");
		else write(cnt[n][c[n]-m]),puts("");
	}
	return 0;
}

T3

T4

正解高斯消元,掌握后再补

posted @ 2021-10-11 08:53  Socratize  阅读(35)  评论(0)    收藏  举报