6.15训练日记

烦心事很多,但打代码一定要心静不能焦躁。平静平静.
惯例,先打卡cf先。

D. Required Length

链接
思路:naive地想,一开始找一个最大的数字嗯乘上去,比如说有一个9,就一直乘9,可能是最优的.但考虑到不是每次都有9,可能需要一些路径先生成一些更大的单个数字.然后考虑到每次都是x*个位数.
那么这个个位数做唯一分解
d i g i t = 2 a ∗ 3 b ∗ 5 c ∗ 7 d digit=2^a*3^b*5^c*7^d digit=2a3b5c7d
可以发现,可能的组合并不多,考虑直接bfs去暴力它.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll n,x;
	cin>>n>>x;
	map<ll,int> dis;
	dis[x] = 0;
	queue<ll> q;q.push(x);
	int ans = -1;
	while(!q.empty()){
		ll y = q.front();
		q.pop();
		string str = to_string(y);
		if(str.length()==n){
			ans = dis[y];
			break; 
		}
		for(auto ch : str){
			if(ch=='0') continue;
			ll nxt = (int)(ch-'0')*y;
			if(!dis.count(nxt)){
				dis[nxt] = dis[y] +1;
				q.push(nxt);
			}
		}
	}
	cout<<ans<<"\n";
}

和某人吵了一架,心情不快,但又无处可泄,遂摆烂.
过三时,幡然醒悟,继续训练.

二:C. Binary String

链接
还是手不太熟,调了比较多的时间.一个比较常见的区间问题和位置经典问题,没有很好地联想到之前学过的一些题目.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
int n,m;
int S[maxn];vector<int> pos;
bool check(int k){
	if(k>=m) return true;
	for(int i=k;i>=0;i--){
		if(k==0){
			if(S[pos[m-1]]-S[pos[0]]<=0) return true;
		}
		else if(i==k){
			int l = pos[k];
			int num = S[pos[m-1]] - S[l];
			if(num<=k) return true;
		}
		else{
			int l = pos[i];
			int r = pos[m+i-k-1];
			int num = S[r] - S[l];
			if(num<=k) return true;
		}
	}
	return false;
}
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T;cin>>T;
	while(T--){
		string s;cin>>s;
		n = s.length();
		pos.clear();
		for(int i=0;i<n;i++){
			S[i+1] = S[i] + (s[i]=='0');
			if(s[i]=='1') pos.push_back(i+1);
		}
		m = pos.size();
		int L = 0,R = m;int ans = m;
		while(L<=R){
			int mid = L+R>>1;
			if(check(mid)) ans=mid,R = mid-1;
			else L = mid+1;
		}
		check(1);
		cout<<ans<<"\n";
	}
}

三:E. Advertising Agency

链接
简单的组合,发现需要贪心地选取前k个大,剩余的可用的和最后剩下的组合数一下就是答案.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<ll,ll> pii;
const ll mod = 1e9+7;
ll fac[maxn];
ll f_pow(ll a,ll b){
	a%=mod;ll ans =1;
	while(b){
		if(b&1) ans = ans*a%mod;
		a=a*a%mod;b>>=1;
	}
	return ans%mod;
}
ll inv(ll n) {
	return f_pow(n,mod-2)%mod;
}
ll C(ll n,ll m){
	return fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod;
}
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	fac[1]=fac[0]=1;
	for(int i=2;i<=1000;i++) fac[i] = fac[i-1]*i%mod;
	int T;cin>>T;
	while(T--){
		int n,k;
		cin>>n>>k;
		map<int,int> cntt;
		for(int i=1;i<=n;i++){
			int x;cin>>x;cntt[x]++;
		}
		vector<pii> vec;
		for(auto [x,y]:cntt){
			vec.push_back({x,y});
		}
		sort(vec.begin(),vec.end());
		reverse(vec.begin(),vec.end());
		ll ans = 1;
		for(auto [x,cnt]:vec){
			if(k>=cnt) k-=cnt;
			else {
				ans=(C(cnt,k)%mod);
				break;
			}
		}
		cout<<ans<<"\n";
	}
}

看了洛谷的一题Tarjan,没有想好,先玩会游戏吃个饭,休息好了回来继续写.
玩了一会刺客信条,育碧罐头果然吃不动,打开戴森球又觉得没有时间玩,看来以后休息还是玩玩手游看看书罢了.

五:嗅探器

链接
题意:给你一个无向图,有两个特殊的点 s , t s,t s,t.求点 u u u,使得去掉 u u u后,s与t不再连通.
思路:一开始理解题意倒是挺困难的.简化为上面的问题后,不难想到割点的定义.
根据割点的定义,如果去掉某个割点后,形成的两个新的连通分量分别包含了 s , t s,t s,t两点在两部分,就满足了定义.去掉割点后,大致形成了三个部分,第一个部分是和根节点连接的,第二个部分是u的子树系列,第三部分是形成割点边u->v的那个双连通分量和下边的子树.
如果我们从s开始跑Tarjan,那么s就是根在第一部分,如果t在第二部分,其实并不能保证它一定和s,t割掉u后不连通,这个部分需要对应的那个割点来判定,唯一可以知道的,如果t在第三部分,那么割掉u后,s,t就会不再连通.
说了这么多,就是在Tarjan找到割点的时候,再判一下有没有
d f n [ v ] < = d f n [ b ] dfn[v]<=dfn[b] dfn[v]<=dfn[b]

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
vector<int> G[maxn];
int dfn[maxn],low[maxn],dfs_clock=0;
bool is_cut[maxn];
int s,t;
void dfs(int u,int fa){
	low[u] = dfn[u] = ++dfs_clock;
	int child = 0;
	for(auto v :G[u]){
		if(!dfn[v]){
			child++;
			dfs(v,u);
			low[u] = min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				if(dfn[t]>=dfn[v]) is_cut[u] = true;
			}
		}
		else if(dfn[v]<dfn[u]&&v!=fa){
			low[u] = min(low[u],dfn[v]);
		}
	}
	if(fa==0&&child==1) is_cut[u] = false;
}
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n,uu,vv;cin>>n;
	while(cin>>uu>>vv){
		if(uu==0&&vv==0) break;
		G[uu].push_back(vv);
		G[vv].push_back(uu);
	}
	cin>>s>>t;
	dfs(s,0);
	int ans = -1;
	for(int i=1;i<=n;i++){
		if(is_cut[i]){
			if(i!=s&&i!=t){
				ans = i;
				break;
			}
		}
	}
	if(ans!=-1) cout<<ans<<"\n";
	else cout<<"No solution\n";
}

今天就这样结束了,心情还不是很好吧,但还是尽量不要让其他事干扰训练,16训练加油

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minato_yukina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值