noip模拟赛三

noip模拟赛三

\(3/11\) 外校大佬不要我们了呜呜呜,挂了 \(160pts\),差点超过自己总分,唐丸了

T1 超市抢购

继续签到,诶我怎么还拿了个首杀

CODE
#include<bits/stdc++.h>
#define llt long long
const llt maxn=10001000;
using namespace std;
llt n,a[maxn],b[maxn],randseed,ans;
unsigned int rnd()
{
  unsigned int r;
  r = randseed = randseed * 1103515245 + 12345;
  return (r << 16) | ((r >> 16) & 0xFFFF);
}
int main()
{
	#ifdef LOCAL
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
	cin>>n>>randseed;
	int sum=0;
	for (int i=n;i>=1;i--)
	{
		a[i]=rnd()%1000,b[i]=rnd()%1000;
		if (sum+(a[i]-b[i])<0) swap(a[i],b[i]);
		sum+=(a[i]-b[i]);
	}
	for(int i=1;i<=n;i++)
	{
		a[i]-=b[i];
		if(a[i]<0)	a[i+1]+=a[i],ans-=a[i];
	}
	printf("%lld\n",ans);
}

T2 核酸检测

我趣,这题赛时竟然没人有分,就喜欢往T2塞难题是吧

就是我们发现 \(n\) 很小,所以对于左端点一样的线段留一个右端点最小的就好了然后就可以暴力 \(O(n^2)\) dp了

\[dp_i=\min_{f(i,j)=0,j<i}{dp_j+1} \]

这里 \(f(i,j)\) 表示 \(i\)\(j\) 中间有完全包含的线段

知道答案之后就很好统计方案数了,只要从符合上面条件并且 \(dp_j=dp_i-1\) 的位置转移就好了

赛时1h就把t1 t2全写完了,然而写了个厌氧程序上去,本地全过了,交上去爆零了,赛后关了O2过了,鉴定为挂了 \(100pts\),荣获最唐称号

CODE
#include<bits/stdc++.h>
#define llt long long
const llt N=500100; 
const llt mod=1e9+7;
using namespace std;
llt to[N],n,l,r,dp[1050],c[1050],m,ans=1e18,minn,oo;bool jud;
int main()
{
    #ifdef LOCAL
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
	scanf("%lld",&n);memset(to,0x3f,sizeof(to));
	for(int i=1;i<=n;i++)	scanf("%lld%lld",&l,&r),to[l]=min(r,to[l]),m=max(r,m);
	c[0]=1;
	for(int i=1;i<=m;i++)
	{
		minn=dp[i-1];
		for(int j=i-1;j>=1;j--)
			if(to[j]>=i)	minn=min(minn,dp[j-1]);
			else break;
		dp[i]=minn+1;
		if(minn==dp[i-1])	c[i]=(c[i]+c[i-1])%mod;
		for(int j=i-1;j>=1;j--)
			if(to[j]>=i)	{if(dp[j-1]+1==dp[i])	c[i]=(c[j-1]+c[i])%mod;}
			else break;
	}
	for(int i=1;i<=m;i++)
	{
		jud=1;
		for(int j=i+1;j<=m;j++)
			if(to[j]<=m)	{jud=0;break;}
		if(jud)	ans=min(dp[i],ans);
	}
	for(int i=1;i<=m;i++)
	{
		jud=1;
		for(int j=i+1;j<=m;j++)
			if(to[j]<=m)	{jud=0;break;}
		if(jud&&dp[i]==ans)	oo=(oo+c[i])%mod;
	}
	printf("%lld\n%lld\n",ans,oo);
    return 0; 
}

T3 七龙珠

一眼丁真,STL题,先跑背包算出可能凑出的龙珠大小,之后跑优先队列bfs加map去重就是正解了

但是出题人把背包复杂度卡到 \(7e9\) 是什么意思,出卡常题是吧,因为不会用bitset顺利T掉两个点,@xrlong 说他没用bitset过了,我常数大算我菜,好吧,那我就是菜

CODE
#include<bits/stdc++.h>
#define llt long long
const llt N=500100; 
const llt mod=1e9+7;
using namespace std;
struct node
{
    llt val,p[10];
    friend bool operator<(const node &x,const node &y)
    {
        if(x.val!=y.val)    return x.val<y.val;
        for(int i=1;i<=7;i++){if(x.p[i]!=y.p[i])  return x.p[i]<y.p[i];}
        return 0;
    }
}u,t,d;
llt m,k,q[10],c[10],b[N],siz,l[10],sum;bitset<N> dp;vector<llt>vec[10],ans;
priority_queue <node> qu;
map<node,bool> vis;
void bfs()
{
    while(!qu.empty()&&siz<k)
    {
        t=qu.top();qu.pop();
        ans.push_back(t.val);siz++;
        for(int i=1;i<=7;i++)
        {
            d=t;
            if(t.p[i]!=l[i]-1)
            {
                d.p[i]++;
                d.val=d.val-vec[i][t.p[i]]*q[i]+vec[i][d.p[i]]*q[i];
                if(vis[d]==1)   continue;
                qu.push(d);vis[d]=1;
            }
        }
    }
    if(siz==k)  printf("%lld\n",ans[siz-1]);
    else    puts("Stop dreaming xm!");
}
int main()
{
    #ifdef LOCAL
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    scanf("%lld%lld",&m,&k);
    for(int i=1;i<=7;i++)   scanf("%lld",&q[i]);
	for(int i=1;i<=7;i++)
    {
        scanf("%lld",&c[i]);sum=0;
        for(int j=1;j<=c[i];j++)    scanf("%lld",&b[j]);
        dp[0]=1;
        for(int j=1;j<=c[i];j++)
            dp|=(dp<<b[j]);
        if(q[i]>0)  {for(int k=m;k>=0;k--)   if(dp[k])   vec[i].push_back(k);}
        else        {for(int k=0;k<=m;k++)   if(dp[k])   vec[i].push_back(k);}
        l[i]=vec[i].size();
        for(int k=0;k<=m;k++)   dp[k]=0;
    }
    for(int i=1;i<=7;i++)   u.p[i]=0,u.val+=vec[i][0]*q[i];
    vis[u]=1;qu.push(u);bfs();
    return 0; 
}

T4 龙珠游戏

还是区间 dp

是某年某月某日普及组模拟赛 T4 存下来行动次数延迟计算的trick,当时场上就切了,一眼想到dp,糊了个逆天记忆化结果发现是 \(O(n^4)\) 的,急着玩蛇懒得去改,卡了卡常感觉起码能过 \(80pts\),剩下的分爱有没有交了,结果大样例太水,所有样例都过了之后交上去全 WA 了,只剩下 \(20pts\) 不如暴力

简单来说就是我们发现神龙在中间取珠子对小明现在是没有啥影响的,直接存储神龙现在有多少次行动没算,到时候再算就好,让神龙也从边上取,只不过可以存着之前的行动连续取,每个状态只需要遍历一遍,\(O(n^3)\) 就过了

CODE
#include<bits/stdc++.h>
#define llt long long
const llt N=500100; 
const llt inf=4557430888798830399;
using namespace std;
llt v[N],dp[510][510][510],n;
llt solve(llt a,llt b,llt c)
{
	llt bestl=1e18,bestr=1e18;
	if(c<0)	return 1e18;
	if(dp[a][b][c]!=inf)	return dp[a][b][c];
	if(a==b&&c!=1)	return 1e18;
	if(a==b&&c==1)	return 0;	
	bestl=min(solve(a+1,b,c+1)+v[a],solve(a+1,b,c-1));
	bestr=min(solve(a,b-1,c+1)+v[b],solve(a,b-1,c-1));
	dp[a][b][c]=max(bestl,bestr);
	return dp[a][b][c];
}
int main()
{
    #ifdef LOCAL
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)	scanf("%lld",&v[i]);
	memset(dp,0x3f,sizeof(dp));
	printf("%lld\n",solve(1,n,0));
    return 0; 
}

<\details>

posted @ 2024-07-11 15:27  wang54321  阅读(15)  评论(0编辑  收藏  举报