Codeforces Round 893 (Div. 2)

A.首先题目意思就是看谁拥有的按钮多,所以优先按c的按钮,按两次c等于没按,所以最后看c的奇偶,奇数代表第一个人能多拥有一个,最后判断第一个人和第二个人拥有的总数即可

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
int n,m,k;

void solve(){
    int a,b,c;cin>>a>>b>>c;
    a+=c%2;
    if(a>b) cout<<"First\n";
    else cout<<"Second\n";
}

signed main(){
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

B.枚举删除的是那个商店

因为a[i]点一定会吃蛋糕,所以我们只需要计算a[i]-1-a[i-1]的距离需要吃多少蛋糕即可

因为我们插入一个1和n+1

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
int n,m,k,d;
int a[N];
void solve(){
	cin>>n>>m>>d;	
	for(int i=1;i<=m;i++) cin>>a[i];
	a[0]=1;a[m+1]=n+1;
	int s=1;
	for(int i=1;i<=m+1;i++)
	{
	    s+=(a[i]-a[i-1]-1)/d;
	    if(i!=m+1&&a[i]!=1)  
	    s++;
	}
   
	int res=2e18,cnt=0;
	for(int i=1;i<=m;i++)
	{
	    int sum=s;
	    sum-=(a[i]-a[i-1]-1)/d+(a[i+1]-a[i]-1)/d;
	    sum+=(a[i+1]-a[i-1]-1)/d;

	    if(a[i]!=1) sum--;
	    if(res>sum) res=sum,cnt=1;
	    else if(res==sum) cnt++;
	}
	cout<<res<<" "<<cnt<<"\n";
}

signed main(){
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

C.

首先构造题无脑打表

额其实好像看不出来啥,但是有个提示

比如排列 1 2 3 6 4 8 57可以换成

1 2 4 8 3 6 5 7

可以观察到 2>4>8>16>32=gcd(2,4,8,16,gcd(32,2))且不会得到重复的gcd

所以大概思路就是每次以某个质因子为起点*2,直到>n

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10,mod=1e9+7;

typedef long long LL;
typedef pair<int, int> PII;
int n,m,k,d;
void solve(){
	cin>>n;
	vector<int> st(n+10,false);
	st[1]=1;
    for(int i=1;i<=n;i++){
        if(i==1) cout<<1<<" ";
        else{
            if(st[i]) continue;
            int x=i;
            while(x<=n){
                cout<<x<<" ";
                st[x]=true;
                x*=2;
            }
        }
    }
    cout<<"\n";
}

signed main(){
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

D.首先最长的连续0和连续1肯定不会相交

所有要么0在前,1在后,要么0后1前

所以大概思路就是预处理出

前i颗树,用了j次,0和1的最长前缀连续长度

和后i棵树用了j次,0和1的最长后缀连续长度

然后直接枚举l0为0到n的个数,此时答案就是

max(a*l0前缀个数+l1后缀的个数,a*I0后缀个数+I1前缀个数)

解释一下方程

dp1:前i个树,用了j次,且以i结尾的最长连续长度 

如果s[i]==s[i-1] 

dp1[i][j]=max(dp1[i][j],dp1[i-1][j]+1)

else:dp1[i][j]=max(dp1[i][j],dp1[i-1][j-1]+1)(j-1>=0)

f:前i个树用了j次的最长前缀长度

以1到i结尾的最长连续长度(dp1[1][j]到dp1[i][j])的最大值

g:后i个树用了j次的最长后缀长度

同上同理

t就是代表当前是I0的长度还是I1的长度

最后统计一下l0从1到n里面 I1最大值即可

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10,mod=1e9+7;

typedef long long LL;
typedef pair<int, int> PII;
int n,m,k,d;
void solve(){
	cin>>n>>k;
	string s;cin>>s;
    
	vector<vector<array<int,2>>> f(n+1,vector<array<int,2>>(k+1));
	vector<vector<array<int,2>>> g(n+1,vector<array<int,2>>(k+1));

      auto get = [&](vector<vector<array<int, 2> > > &dp)
        {
            vector<vector<array<int,2>>> dp1(n+1,vector<array<int,2>>(k+1));
            for(int i = 0; i <n; i++){
                for(int j = 0; j <= k; j++){
                    for(int t = 0; t < 2; t++)
                    {
                        dp[i+1][j][t]=max(dp[i+1][j][t],dp[i][j][t]);
                        if(s[i]-'0'==t)
                        {
         dp1[i + 1][j ][t] = max(dp1[i + 1][j ][t], dp1[i][j][t] + 1);
        dp[i+1][j][t]=max(dp[i+1][j][t],dp1[i+1][j][t]);
                        }
                        else
                        {
                            if(j+1<=k)
                            {
            dp1[i + 1][j + 1][t] = max(dp1[i + 1][j + 1][t], dp1[i][j][t] + 1);
        dp[i+1][j+1][t]=max(dp[i+1][j+1][t],dp1[i+1][j+1][t]);
                            }
                        }
                        
                    }
                }
            }
        };
    get(f);
    reverse(s.begin(),s.end());
    get(g);
    
    vector<int> suf(n+10,-2e9);
    vector<bool> st(n+10,false);
    for(int i=1;i<=n;i++){
        for(int j=0;j<=k;j++){
            for(int t=0;t<2;t++)
            {
                int mx1=f[i][j][t];
                int mx2=g[n-i][k-j][t^1];
                if(t) swap(mx1,mx2);
                st[mx1]=true;
                suf[mx1]=max(suf[mx1],mx2);
            }
        }
    }
    for(int i=n;i>=0;i--)
    suf[i]=max(suf[i+1],suf[i]);
    
    vector<int> res(n+1,0);
    for(int i=0;i<=n;i++)
    {
        if(!st[i]) continue;
        for(int j=1;j<=n;j++)
        {
            res[j]=max(res[j],j*i+suf[i]);
        }
    }
    for(int i=1;i<=n;i++)
    cout<<res[i]<<" \n"[i==n];
}

signed main(){
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

E.给定一个序列

添加一个数相当于上个点和当前点链接一条边,添加一个点

-k就是往上跳k步(可以用倍增处理)

回滚(跳到上一次的点,记录一下上一次到达的点即可)

?(从根节点到当前节点的不同数的个数)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=1e9+7;

typedef long long LL;
typedef pair<int, int> PII;
int n,m,k,d;
vector<int> g[N],query[N];
int fa[20][N];
int ans[N],a[N],cnt[N],sum;
void dfs(int u){
    if (u != 1)
    {
        if (++cnt[a[u]] == 1)
        {
            sum += 1;
        }
    }
    for(auto x : query[u]) ans[x] = sum;
    for(auto j : g[u]) dfs(j);
    if (u != 1){
        if (--cnt[a[u]] == 0){
            sum -= 1;
        }
    }
}
void solve(){
    cin >> n;
    int tot = 1, cur = 1, qs = 0;
    vector<int> ops;
    ops.reserve(n);
    ops.push_back(cur);
    for(int i = 0; i < n; i++){
        char op;
        cin >> op;
        if (op == '+'){
            int x;
            cin >> x;
            a[++tot] = x;
            fa[0][tot] = cur;
            for(int j = 1; j <= 19; j++)
                fa[j][tot] = fa[j - 1][fa[j - 1][tot]];
            g[cur].push_back(tot);
            cur = tot;
            ops.push_back(cur);
        }
        else if (op == '-')
        {
            int k;
            cin >> k;
            for(int j = 19; j >= 0; j--){
                if (k >> j & 1){
                    cur = fa[j][cur];
                }
            }
            ops.push_back(cur);
        }
        else if (op == '!')
        {
            ops.pop_back();
            cur = ops.back();
        }
        else{
            query[cur].push_back(++qs);
        }
    }
    dfs(1);
    for(int i = 1; i <= qs; i++)
        cout << ans[i] << '\n';
}

signed main(){
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
   // cin>>t;
    while(t--) solve();
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值