2021 10.9 模拟测试 *

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
正解高斯消元,掌握后再补

浙公网安备 33010602011771号