上蓝训练(1600-1800)

A. Extreme Subtraction

  • 题意
    在这里插入图片描述
  • 思路
    对序列的区间操作,考虑到转化到两点上去,而且全 0 0 0 意味着差分数组是 0 0 0 且第一个数是 0 0 0。 由此尝试差分。
    d [ 1 ] = a [ 1 ] d[1]=a[1] d[1]=a[1]
    对操作一而言,差分使得 d [ 1 ] − 1 , d [ i + 1 ] + 1 d[1]-1,d[i+1]+1 d[1]1,d[i+1]+1;也就是使得序列中的差分数是负数的变成正数。
    对于操作二而言,差分使得 d [ i ] − 1 , d [ n + 1 ] + 1 d[i]-1,d[n+1]+1 d[i]1,d[n+1]+1; 也就是使得序列中的差分数是正数的变成负数。
    那么要想差分数组全是 0 0 0,首先要让除 d [ 1 ] d[1] d[1] 外的数组都是 0 0 0 ,因为我们可以无限次对 d [ 1 ] d[1] d[1] 操作。那么也就是能够满足让 d [ 2 − n ] d[2-n] d[2n] 中都为 0 0 0,负数加到 0 0 0,正数减到 0 0 0.
    即考虑第一个数大小能不能 > = >= >= 后面差分数的负数的绝对值的和。
  • 思路2
#include<bits/stdc++.h>
using namespace std;
const int N=3e4+100;
int a[N];
int pre=-1;
int main(){
	int T;scanf("%d",&T);
	while(T--){
		bool f=true;
		int n;scanf("%d",&n);
		for(int i=0;i<n;i++) scanf("%d",&a[i]);
		int i;
		for(i=1;i<=n;i++){
			if(a[i]>a[i-1]){
				a[i]-=a[i-1];
				pre=a[i-1];
				for(int j=i+1;j<n;j++){
					if(a[j]<a[j-1]){
						f=false;
						break;
					}
					if(a[j]-pre<=a[j-1]){
						pre=a[j]-a[j-1];
						a[j]=a[j-1];
					}
					else{
						a[j]-=pre;
					}
				}
				break;
			}
		}
		if(f) puts("YES");
		if(!f) puts("NO");
	} 
	return 0;
}

B Sasha and One More Name

  • 题意
    把一个字符串切成 k + 1 k+1 k+1 块,使得这 k + 1 k+1 k+1 块随意排序后,得到的新字符串是个回文串。
  • 思路
    在这里插入图片描述
D Beautiful Graph
  • 题意
    在这里插入图片描述- 没看题解前想法
    树形 D P DP DP
    d p [ f a ] [ 1 ] ∗ = d p [ s o n ] [ 2 ] ∗ 2 d p [ f a ] [ 2 ] ∗ = d p [ s o n ] [ 1 ] dp[fa][1] *= dp[son][2]*2 \\dp[fa][2] *= dp[son][1] dp[fa][1]=dp[son][2]2dp[fa][2]=dp[son][1]
    果然错了
  • 正解
    深搜
  • 官方代码
#include <bits/stdc++.h>
 
using namespace std;
 
const int N = int(3e5) + 999;
const int MOD = 998244353;
 
int n, m;
vector <int> g[N];
int p2[N];
int cnt[2];
int col[N];
bool bad;
 
void dfs(int v, int c){
    col[v] = c;
    ++cnt[c];
    for(auto to : g[v]){
        if(col[to] == -1) dfs(to, 1 - c);
        if((col[v] ==col[to]) )
            bad = true;
    }
} 
int main() {
    p2[0] = 1;
    for(int i = 1; i < N; ++i)
        p2[i] = (2 * p2[i - 1]) % MOD;
        
    int tc;
    scanf("%d", &tc);
    while(tc--){
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; ++i)
            g[i].clear();
        
        for(int i = 0; i < m; ++i){
            int u, v;
            scanf("%d %d", &u, &v);
            --u, --v;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        
        int res = 1;
        for(int i = 0; i < n; ++i) col[i] = -1;
        for(int i = 0; i < n; ++i){
            if(col[i] != -1) continue;
            bad = false;
            cnt[0] = cnt[1] = 0;
            dfs(i, 0);
            if(bad){
                puts("0");
                break;
            }
            int cur = (p2[cnt[0]] + p2[cnt[1]]) % MOD;
            res = (res * 1LL * cur) % MOD;
        }
        
        if(!bad) printf("%d\n", res);
    }
    
    return 0;
}


  • 自己的代码
#include <bits/stdc++.h>

using namespace std;
const int N = 300010,mod = 998244353;
#define int long long 
vector<int> edge[N];
int cnt[3];
int color[N];
bool flag = true;
int p[N];
void dfs(int u,int c) 
{
	cnt[c] ++;
	for (auto v:edge[u]) {
		if (!color[v]) {
			color[v] = 3-c;
			dfs(v,3-c);
		} else {
			if (color[v] == color[u]) {
				flag = true;return;
			}
		}
	}
	return ;
}

void solve()
{
	int n,m; cin>>n>>m;
	for (int i = 1;i <= n;i ++) {
		edge[i].clear();
		color[i] = 0;
	}
	for (int i = 1;i <= m;i ++) {
		int u,v; cin>>u>>v;
		edge[u].push_back(v);
		edge[v].push_back(u);
	}
	int ans = 1;
	for (int i = 1;i <= n;i ++) {
		flag = false;
		cnt[1] = 0,cnt[2] = 0;
		if (!color[i]) {
			color[i] = 1;
			dfs(i,1);
			if (flag) {
				cout<<0<<endl;
				return ;
			}
			ans = ans * ((p[cnt[1]] + p[cnt[2]]) % mod) % mod;
		}
	} 
	cout<<ans<<endl;
}

signed main()
{
	p[0] = 1;
	for (int i = 1;i < N;i ++) {
		p[i] = p[i-1] * 2 % mod;
	}
	int t;cin>>t;
	while (t --) {
		solve();
	}
}

C Vasya and Robot

  • 题意
    在这里插入图片描述

  • 初始思路
    二分长度,然后找到一个区间中左右方向各自等于 x , y x,y x,y的绝对值。

  • 正解
    差不多了,就是要处理出一个前缀和的东西类似于。

  • 官方代码

#include <bits/stdc++.h>

using namespace std;

const int N = int(1e5) + 9;

string s;
int n;
int x, y;

void upd(pair<int, int> &pos, char mv, int d){
	if(mv == 'U')
		pos.second += d;
	if(mv == 'D')
		pos.second -= d;
	if(mv == 'L')
		pos.first -= d;
	if(mv == 'R')
		pos.first += d;
}

bool can(pair<int, int> u, pair<int, int> v, int len){
	int d = abs(u.first - v.first) + abs(u.second - v.second);
	if(d % 2 != len % 2) return false;
	return len >= d;
}

bool ok(int len){
	pair<int, int> pos = make_pair(0, 0);
	for(int i = len; i < n; ++i)
		upd(pos, s[i], 1);

	int l = 0, r = len;
	while(true){
		if(can(pos, make_pair(x, y), len))
			return true;
		
		if(r == n) break;
		upd(pos, s[l++], 1);
		upd(pos, s[r++], -1);		
	}
	
	return false;
}

int main() {
	//freopen("input.txt", "r", stdin);
	
	cin >> n;
	cin >> s;
	cin >> x >> y;
	
	if(!ok(n)){
		puts("-1");
		return 0;
	}
	
	int l = -1, r = n;
	while(r - l > 1){
		int mid = (l + r) / 2;
		if(ok(mid)) r = mid;
		else l = mid;
	}
	
	cout << r << endl;
    return 0;
}

A Enlarge GCD

  • 题意
    在这里插入图片描述

  • 初始思路
    全部除以原始 G C D GCD GCD。然后对于每个数分解质因数,然后从质因数出现次数最多的,就是解。然后 n n n 减去这个数就是正式答案。

  • 对了对了,以前的 1800 1800 1800 就是简单呀。

  • 官方代码

#include<bits/stdc++.h>
using namespace std;
#define MN 300000
#define MX 15000000
int a[MN+5],u[MX+5],p[MX+5],pn,s[MX+5];
int gcd(int x,int y){return y?gcd(y,x%y):x;}
int main()
{
	int n,i,j,g,x,ans=0;
	for(i=2;i<=MX;++i)
	{
		if(!u[i])u[i]=p[++pn]=i;
		for(j=1;i*p[j]<=MX;++j){u[i*p[j]]=p[j];if(i%p[j]==0)break;}
	}
	scanf("%d",&n);
	for(g=0,i=1;i<=n;++i)scanf("%d",&a[i]),g=gcd(g,a[i]);
	for(i=1;i<=n;++i)for(j=a[i]/g;j>1;)for(++s[x=u[j]];u[j]==x;)j/=u[j];
	for(i=1;i<=MX;++i)ans=max(ans,s[i]);
	printf("%d",ans?n-ans:-1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

疯狂的码泰君

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

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

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

打赏作者

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

抵扣说明:

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

余额充值