AtCoder Beginner Contest 271

尽量写的高质量一点,只写有意义的题目。

C

可以像题解一样 通过二分来解决本题,这里提供一个 桶+双指针 的解法。
先将书的序号排序,将相同的放在最后(unique 函数),用桶维护共有哪些书,两个指针分别维护从前面读了几本书 和 从后面换了几本书,每次模拟换书的过程需要更新桶数组。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,a[N],tong[N];
signed main()
{
	cin>>n;
	for(int i=1;i<=n;++i)cin>>a[i];	
	sort(a+1,a+n+1);unique(a+1,a+n+1);
	for(int i=1;i<=n;++i)if(a[i]<=n)tong[a[i]]++;
	int i,hav=0,lst=n;
	for(i=1;i<=n;++i)
	{
		if(tong[i]){hav++;continue;}
		if(hav>lst-2)break;
		if(a[lst]<=n)tong[a[lst]]--;
		if(a[lst-1]<=n)tong[a[lst-1]]--;
		lst-=2;
	}
	cout<<i-1;
	return 0;
}

D

考虑 dp,设 dp[i][j] 表示前 i 个数总和为 j 是否有方案。
转移:dp[i][j]∣=dp[i1][ja[i]],dp[i][j]∣=dp[i1][jb[i]]
考虑如何输出方案,我们可以倒序模拟 dp 的过程,每次看 dp[i1][ja[i]]dp[i1][jb[i]] 是否为 1,用栈记录每次的选择,最后输出即可。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,k,a[105],b[105];
bool dp[105][10005];
signed main()
{
	cin>>n>>k;
   	for(int i=1;i<=n;++i)
   		cin>>a[i]>>b[i];
    dp[0][0]=1;
    for(int i=1;i<=n;++i) 
		for(int j=0;j<=k;++j)
	    {
	        if(j-a[i]>=0)dp[i][j]|=dp[i-1][j-a[i]];
	        if(j-b[i]>=0)dp[i][j]|=dp[i-1][j-b[i]];
	    }
    if(dp[n][k])cout<<"Yes\n";
    else cout<<"No\n";
    stack<char>s;
    if(dp[n][k])
    {
        int nown=n,nowk=k;
        while(nown)
        {
            if(a[nown]<=nowk&&dp[nown-1][nowk-a[nown]])
            {
                s.push('H');
                nowk-=a[nown];
                nown--;
            } 
            else if(b[nown]<=nowk&&dp[nown-1][nowk-b[nown]])
            {
                s.push('T');
                nowk-=b[nown];
                nown--;
            }
        }
    }
    for(;!s.empty();s.pop())putchar(s.top());
    return 0;
}

E

容易想到 dp。
考虑朴素的 dp,设 dp[i][j] 表示当前在 i 点,当前用的边的序列是 E[1]E[j] 的子序列的最小花费。
转移:dp[v][j]=min(dp[v][j1],dp[u][j1]+len(u,v)(u,v)==E[j])
滚动数组一下:dp[v]=min(dp[v],dp[u]+len(u,v)(u,v)E)
观察发现第二种决策可行 当且仅当 (u,v) 这条边在 E 中,所以只更新 E 中的 k 条边即可。

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,m,k,u[N],v[N],w[N],f[N];
signed main()
{
	memset(f,0x3f,sizeof(f));
	cin>>n>>m>>k;
	for(int i=1;i<=m;++i)cin>>u[i]>>v[i]>>w[i];
	f[1]=0;
	while(k--)
	{
		int x;cin>>x;
		f[v[x]]=min(f[v[x]],f[u[x]]+w[x]);
	}
	if(f[n]==4557430888798830399)cout<<-1;
	else cout<<f[n];
	return 0;
} 

F

发现 (1,1)(n,n) 的路径长为 2n2,直接搜索复杂度为 O(22n2),会超时,考虑折半搜索。
(1,1)(n,n) 分别开始搜索,搜 n1 步,用前缀和记录走到每个汇合点不同答案的方案数,再把两边拼起来即可。时间复杂度为 O((n1)2n1)

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,a[30][30];
signed main()
{
    cin>>n;
    for(int i=1;i<=n;++i)
    	for(int j=1;j<=n;++j)
    		cin>>a[i][j];
    map<int,int>qz[30][30],qz2[30][30];
    for(int i=0;i<(1<<(n-1));++i)
    {
        int x=1,y=1,ans=0;
        for(int s=0;s<=n-2;++s)
        {
            ans^=a[x][y];
            if(i&(1<<s))x++;
            else y++;
        }
        qz[x][y][ans]++;
    }
    for(int i=0;i<(1<<(n-1));++i)
    {
        int x=n,y=n,ans=0;
        for(int s=0;s<=n-2;++s)
        {
            if(i&(1<<s))x--;
            else y--;
            ans^=a[x][y];
        }
        qz2[x][y][ans^a[n][n]]++;
    }
    int cnt=0;
    for(int i=1;i<=n;++i)
    	for(int j=1;j<=n;++j)
		{
	        map<int,int>::iterator from=qz[i][j].begin();
	        map<int,int>::iterator to=qz[i][j].end();
	        while(from!=to)
	        {
	            int key=from->first,val=from->second;
	            cnt+=val*qz2[i][j][key];from++;
	        }
	    }
    cout<<cnt;
    return 0;
}

posted @   lnwhl  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示