[算法学习记录] ABC401 A-E

A - Status Code
根据题意模拟即可

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

void solve()
{
	int s;cin >> s;
	if(s>=200&&s<=299)cout <<"Success\n";
	else cout << "Failure\n";
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

B - Unauthorized
还是根据题意模拟

#include<bits/stdc++.h>
using namespace std;
using ll = long long; 

void solve()
{
	int n;cin >> n;
	
	int ans = 0;
	bool sta = false;
	while(n--)
	{
		string s;cin >> s;
		if(s=="login") sta = true;
		if(s=="logout") sta = false;
		if(s=="private"&&!sta) ans++;
	}
	
	cout << ans <<"\n";
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

C - K-bonacci
可以用双端队列动态维护当前元素的值,也可以用前缀和解答。

双端队列

点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int p = 1e9;
vector<ll> num;

void solve()
{
	ll n,k;cin >> n >> k;
	
	if(n<k)
	{
		cout << 1 <<"\n";
		return;	
	}
	
	deque<ll> dq; 
    ll sum = 0;
    
    for(int i = 0; i < k; ++i)
    {
        dq.push_back(1);
        sum = (sum + 1) % p;
    }
    //预处理
    for(int i = k; i <= n; ++i)
    {
        ll c = sum;
        dq.push_back(c);
        sum = (sum + c) % p;
        //更新首部元素
        if(dq.size() > k)
        {
            sum = (sum - dq.front() + p) % p;
            //模运算可能会出现负数,加个p防止爆long long
            dq.pop_front();
            //弹出尾部元素
        }
        //得到新的k项和
    }
    
    cout << dq.back() << "\n";
    //输出队首元素
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

前缀和

点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6+5;
const ll p = 1e9;
ll a[N];

void solve()
{
	int n,k;cin >> n >> k;
	
	for(int i = 1;i<=k;i++)a[i] = a[i-1] + 1;
	
	for(int i = k + 1;i<=n+1;i++) a[i] = (2*a[i-1] - a[i - k - 1]) % p;
	//a[]数组就是前缀和数组
	cout << (a[n+1] - a[n] + 2*p)%p <<"\n";
    //前缀和求特定区间值(加2*p是为了防止出现负数,同时也为了满足题意)
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

D - Logical Filling


本题已保证X不为空,所以我们只需考虑X存在的情况即可。
因为o不能相邻,所以o两端的字符就是确定的,所以我们可以先处理o两端的字符;
这样我们就得到一个新字符串\(S'\),以及一个新条件\(k'\)
至此,我们要做的事就变成了确定如何把\(k'\)o放入若干个由?构成的区间区间中;
假设每一个区间的长度为\(l_i\),那么每一个区间最多可以容纳的o的个数为\(\lceil \frac {l_i}{\over2} \rceil\)
该字符串所能容纳o的最大数量为\(\sum_{i=1}^{m} l_i\),其中\(m\)为符合条件的区间的数量。
由于X一定存在,所以$ cnt\leq k$
\(k=0\)时,所有的?就只能是.,只有一种可能;
\(k=cnt\)时,分两种情况;

  • \(cnt\)为奇数,那么就只有形如o.o.o的一种可能
  • \(cnt\)为偶数,那么就有两种可能一种是.o.o.o另一种是o.o.o.,每个位置都不能确定,所有的?依然是?;
    \(k \not= cnt\)时,\(k<cnt\)说明至少有一个区间没有o\(k>0\)说明至少有一个区间非空,也就是说每一个位置都无法确定,所以全部都是?
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
int cnt = 0;

void solve()
{
	int n,k;cin >> n >> k;
	string s;cin >> s;s =  "#" + s + "#";
	//读入字符串,在前后各加一个不相干的字符以简化算法
	for(int i = 1;i<=n;i++)
		if(s[i]=='o')
		{
			s[i-1] = '.';s[i+1] = '.';
            k--;
		}
		//把o的前后都标记为.
	for(int i = 1,l = 0;i<=n;i++)
	{
		if(s[i]=='?'&&s[i-1]!='?') l = i;
		if(s[i]=='?'&&s[i+1]!='?') cnt += (i-l)/2+1;
	}
	//计算该字符串k出现的最多次数(不算初始的)
    if(!k) for(int i = 1;i <= n;i++)if(s[i]=='?') s[i] = '.';
    //k=0的情况
	if(k==cnt)
	{
		for(int i = 1,l = 0;i<=n;i++)
		{
			if(s[i]=='?'&&s[i-1]!='?')l = i;
			if(s[i]=='?'&&s[i+1]!='?')
			{
				if((i-l+1)&1)
                    //?串的长度为奇数,为偶数时不能确定
					for(int j = l;j<=i;j++)
						((j-l+1)&1) ? s[j] = 'o' : s[j] = '.';	
                        //偶数位为o,奇数位为.	
			}
		}
	} 
    //k=cnt的情况 
	for(int i = 1;i<=n;i++)cout << s[i];
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

E - Reachable Set

根据题目描述,可以看出本题可以用并查集解决。
遍历\(1\)~\(k\)
如果存在答案,那么所有的节点都是联通的,也就是说联通块只有一个,我们可以用一个变量\(cnt\)来表示联通块的个数;
如果要符合答案的条件,那么比\(k\)大的点就一定要被删去(只删去与之直接相连的即可),这样计算得出的答案一定是最小值。

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5+5;
int n,m,pre[N],cnt,ans;
bitset<N> vis;
vector<int> g[N];

int root(int u)
{
	return pre[u] = (pre[u] == u ? u : root(pre[u]));
}

void merge(int u,int v)
{
	int x = root(u),y = root(v);
	if(pre[x]!=y)pre[x] = y,cnt--;
} 

void solve()
{
	cin >> n >> m;
	while(m--)
	{
		int u,v;cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for(int i = 1;i<=n;i++)pre[i] = i;
	
	for(int i = 1;i<=n;i++)
	{
		cnt++;
		if(vis[i]) ans--;
        //记得忽略k点本身
		for(auto &p : g[i])
		{
			if(p<i) merge(i,p);
			else if(!vis[p]) vis[p] = true,ans++;
		}
		
		cout << (cnt == 1 ? ans : -1) <<"\n";
        //如果只有一个联通块就符合条件
	}
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}
posted @ 2025-04-15 21:20  林克还是克林  阅读(7)  评论(0)    收藏  举报