【LGR-148-Div.3】洛谷基础赛 #1 & MGOI Round I

【LGR-148-Div.3】洛谷基础赛 #1 & MGOI Round I

T1 luoguP9502 『MGOI』Simple Round I | A. 魔法数字 \(100pts\)

  • 水题,场切了。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long 
    #define sort stable_sort 
    #define endl '\n'
    int main()
    {
    	int n,m;
    	cin>>n;
    	m=log2(n);
    	if((1<<m)==n)
    	{
    		if(m%2==1)
    		{
    			m--;
    		}
    		else
    		{
    			m-=2;
    		}
    	}
    	else
    	{
    		if(m%2==1)
    		{
    			m--;
    		}
    	}	
    	cout<<m;
    	return 0;
    }
    

T2 luoguP9503 『MGOI』Simple Round I | B. 魔法照相馆 \(100pts\)

  • 水题,赛场上不会位运算,就当成大模拟打了,码风凑合看吧,谨慎观看此代码。

  • 可以将 \(if,else\) 压成位运算。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define sort stable_sort
    #define endl '\n'
    int main()
    {
    	ll n,i,ans=0,r=1,b=1,w=1;
    	char pd,en='W';
    	cin>>n;
    	for(i=1;i<=n;i++)
    	{
    		cin>>pd;
    		if(pd!=en)
    		{
    			if(en=='W')
    			{
    				if(pd=='B')
    				{
    					if(b==1)
    					{
    						ans++;
    					}
    					else
    					{
    						ans+=2;
    						b=1;
    					}
    					w=0;
    				}
    				if(pd=='R')
    				{
    					if(r==1)
    					{
    						if(b==1)
    						{
    							ans+=2;
    							b=0;
    						}
    						else
    						{
    							ans++;
    						}
    					}
    					else
    					{
    						if(b==1)
    						{
    							ans+=3;
    							b=0;
    						}
    						else
    						{
    							ans+=2;
    						}
    					}
    					w=0;	
    					r=1;
    				}
    			}
    			if(en=='B')
    			{
    				if(pd=='R')
    				{
    					if(r==1)
    					{
    						ans++;
    					}
    					else
    					{	
    						ans+=2;
    						r=1;
    					}
    					b=0;
    					r=1;
    				}
    				if(pd=='W')
    				{
    					ans+=1;	
    					w=1;
    				}
    			}
    			if(en=='R')
    			{
    				if(pd=='W')
    				{
    					ans+=1;
    					w=1;
    				}
    				if(pd=='B')
    				{
    					ans+=1;
    					b=1;
    				}
    			}
    			en=pd;
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    

T3 luoguP9504 『MGOI』Simple Round I | C. 魔法禁林 \(0pts\)

  • 注意 \(0\le w\le 100\) 这个条件,又因为 扣血方式为\(\left\lfloor \frac{w_i}{k} \right\rfloor\) ,所以易知最多跑 \(100\) 条边(因为 \(k>w_i\) 就不扣血了,能够无伤走到终点,直接返回记录答案即可),故魔力值 \(\le 100\)
  • 正解:以 \(t\) 为起点, \(s\) 为终点,便于确定 \(k\) 的值,跑单源最短路。
    • 考虑给 \(dijkstra\) 中的 \(dis\) 数组增加一维,令 \(dis[i][j]\) 表示当 \(k=i\) 时,走到 \(j\) 的最小生命值。
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define sort stable_sort
    #define endl '\n'
    struct node
    {
        int nxt,to,w;
    }e[90000];
    int head[90000],vis[110][90000],dis[110][90000],cnt=0,ans=0x7f7f7f7f;
    void add(int u,int v,int w)
    {
        cnt++;
        e[cnt].nxt=head[u];
        e[cnt].to=v;
        e[cnt].w=w;
        head[u]=cnt;
    }
    void dijkstra(int s)
    {
        int x,num,i;
        priority_queue<pair<int,pair<int,int> > >q;
        memset(vis,0,sizeof(vis));
        memset(dis,0x3f,sizeof(dis));
        dis[0][s]=0;
        q.push(make_pair(0,make_pair(0,-s)));
        while(q.empty()==0)
        {
            num=-q.top().second.first;
            x=-q.top().second.second;
            q.pop();
            if(num>100)//当走的边数大于100时,直接返回
            {
                ans=min(ans,dis[num][x]);
            }
            else
            {	
                if(vis[num][x]==0)
                {
                    vis[num][x]=1;
                    for(i=head[x];i!=0;i=e[i].nxt)
                    {
                        if(dis[num+1][e[i].to]>dis[num][x]+e[i].w/(num+1))
                        {
                            dis[num+1][e[i].to]=dis[num][x]+e[i].w/(num+1);
                            q.push(make_pair(-dis[num+1][e[i].to],make_pair(-(num+1),-e[i].to)));
                        }
                    }
                }
                
            }
        }
    }
    int main()
    {
        int n,m,s,t,u,v,w,i;
        cin>>n>>m>>s>>t;
        for(i=1;i<=m;i++)
        {
            cin>>u>>v>>w;
            add(u,v,w);
            add(v,u,w);
        }
        dijkstra(t);
        for(i=0;i<=101;i++)
        {
            ans=min(ans,dis[i][s]);
        }
        cout<<ans<<endl;
        return 0;
    }
    

T4 luoguP9505 『MGOI』Simple Round I | D. 魔法环 \(0pts\)

  • 因为涉及变量重复问题,题面中的 \(k\) 此处用 \(m\) 代替。
  • 考虑破坏为链,进行 \(DP\) ,枚举以每个点为起点,令 \(f[i][j]\) 表示前 \(i\) 个中激活了 \(j\) 个精灵产生的附魔值的最小值,枚举上一个被激活的精灵 \(k(1\le k <i)\) 进行状态转移,
    • 得到在 \(1\le j \le i\le n,j<m\) 时, \(f[i][j]=min(f[i][j],f[k][j-1]+max(b[k],b[i])×\sum\limits_{h=1}^{i-k-1}h+b[i]^2)\)
    • 得到在 \(m\le i\le n,j=m\) 时, 因为要满足 至少 激活 \(m\) 个精灵,\(f[i][j]=min(f[i][j],f[k][m]+max(b[k],b[i])×\sum\limits_{h=1}^{i-k-1}h+b[i]^2)\)
    • 这样的复杂度为 $O(n^3k) $,成功 \(\huge TLE\)
  • 有个贪心的结论,激活魔供值为 \(0\) 的精灵一定不劣(因为是否激活 \(0\) 对答案没有影响)。故直接考虑以 \(0\) 为起点,故 \(f[1][1]=0^2=0\) ,接着进行状态转移。时间复杂度 \(O(n^2k)\) ,卡着时限过。
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define sort stable_sort
    #define endl '\n'
    ll a[3001],b[3001],f[3001][101];//十年OI一场空,不开long long见祖宗
    int main()
    {
    	ll n,m,i,j,k,rt,ans=0x7f7f7f7f;
    	cin>>n>>m;
    	memset(f,0x3f,sizeof(f));//初始化
    	f[1][1]=0;
    	for(i=1;i<=n;i++)
    	{
    		cin>>a[i];
    		if(a[i]==0)
    		{
    			rt=i;
    		}
    	}
    	for(i=1;i<=n;i++)//以0为起点,重新构造
    	{
    		b[i]=a[(i+rt-2)%n+1];
    	}
    	for(i=1;i<=n;i++)
    	{
    		for(j=2;j<=min(i,m);j++)
    		{
    			for(k=1;k<=i-1;k++)
    			{
    				f[i][j]=min(f[i][j],f[k][j-1]+(i-k-1)*(i-k)/2*max(b[k],b[i])+b[i]*b[i]);
    				if(j==m)
    				{
    					f[i][j]=min(f[i][j],f[k][j]+(i-k-1)*(i-k)/2*max(b[k],b[i])+b[i]*b[i]);
    				}
    			}
    		}
    	}
    	for(i=m;i<=n;i++)
    	{
    		ans=min(ans,f[i][m]+(n-i)*(n-i+1)/2*b[i]);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

总结

看清楚题再交,不要像我一样好几次把 \(T3\) 代码交到了 \(T4\)

posted @ 2023-08-07 10:31  hzoi_Shadow  阅读(127)  评论(0编辑  收藏  举报
扩大
缩小