学习笔记10:Codeforces Round 919 (Div. 2)(B-D)

Dashboard - Codeforces Round 919 (Div. 2) - Codeforces

B写崩了

丑陋的代码

删掉一个数一定比把这个数留着乘-1更好

前缀和预处理,从后往前枚举每种情况

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010;
int a[N];
bool st[N];
int sum[N],sum2[N];
void solve(){
    int n,k,x;
    cin>>n>>k>>x;
    sum[0]=0;
    int res=0;
    for(int i=1;i<=n;i++){
    	cin>>a[i];
    	res+=a[i];
    }
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++){
    	sum[i]=sum[i-1]+a[i];
    }
    	int tt=res-2*(sum[n]-sum[n-x]);
    	for(int i=0;i<=k;i++){
    		int ans2=sum[max((int)0,n-i)]-2*(sum[max((int)0,n-i)]-sum[max((int)0,(n-i-x))]);
    		tt=max(tt,ans2);
    	}	
    	
    	cout<<tt<<endl;
}
signed main(){
	
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
}
        

C

分解一下因子,我们假设现在是因子x,每个块的长度都是x,我们需要关心的是是否存在一个m使得 (1,1+x,1+2x…… )(2,2+x,2+2x……)这类块中所有数模m后的余数相等

思考:如何凑出这样一个m?
我们可以把每个块中的差(相邻两数,不是也没关系但一定要保证数与数之间的联通性,因为这样我们可以保证这个正确性),求gcd,因为m对于所有块是固定不会变的,这时gcd不是1,就存在m

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010;
int a[N];
bool st[N];
int sum[N],sum2[N];
void solve(){
    int n,k,x;
    cin>>n;
   	std::vector<int>v;
   	map<int,int>mp;
   	int gg=0;
   	for(int i=1;i<=n;i++){
   		cin>>a[i];
   		gg=__gcd(gg,a[i]);
   		mp[a[i]]++;
   	}
   	for(int i=1;i<=n/i;i++){
   		if(n%i)continue;
   		v.push_back(i);
   		if(i!=n/i){
   			v.push_back(n/i);
   		}
   	}
   	int ans=0;
   	for(auto c:v){
   		int f=1;
		int g=0;
   		for(int i=1;i<=c;i++){
   			//mp<int,int>mp;
   			
   			for(int j=i+c;j<=n;j+=c){
   				if(a[j]==a[i])continue;
   				g=__gcd(abs(a[j]-a[i]),g);
   			}
   			if(g==1){
   				f=0;
   				break;
   			} 
   		}
   		if(f ){
   			ans++;
   		}
   	}
    cout<<ans<<endl;
}
signed main(){	
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
}
        

D

我们用add数组记录直接添加的节点和翻倍时的刚好的倍数节点

dp数组存储现长度

当查询的位置很大时,我们可以在dp数组(从后到前循环,因为翻倍从从前到后)中找到它翻倍之前的长度

情况1:当好是节点上的点,或是通过操作1得到的点,这时直接退出即可,因为这些点我们已经记录下来了

情况2:其他点,说明k是一次翻倍的点,且不是节点,直接对dp数组取模,可以得到k在翻倍前的位置,这时就继续判断如果是情况1则跳出,如果是情况2就继续即可

这这个过程不会太长因为题目限制了1e18的长度,而且是log级别的

#include <iostream>
#include <cstring>
#include <algorithm>
#include<vector>
using namespace std;
#define int long long
void solve(){
    int n,q;
    cin>>n>>q;
    int dp[n+1]={};
    int add[n+1]={};
    vector<int>pos;
    for(int i=1,ok=true;i<=n;i++){
        int op,x;
        cin>>op>>x;
        if(op==1){
            dp[i]=dp[i-1]+1;
            add[i]=x;
        }else{
            if(x+1>2e18/dp[i-1]){
                dp[i]=2e18;
            }else{
                dp[i]=dp[i-1]*(x+1);
            }
            add[i]=add[i-1];
            if(ok) pos.push_back(i);
        }
        if(dp[i]==2e18) ok=false;
    }
    while(q--){
        int k;
        cin>>k;
        for(int i=pos.size()-1;i>=0;i--){
            int idx=pos[i];
            if(dp[idx] >k && dp[idx-1]<k){
                if(k%dp[idx-1]==0){
                    k=dp[idx-1];
                    break;
                }
                k%=dp[idx-1];
            }
        }
        cout<<add[lower_bound(dp+1,dp+1+n,k)-dp]<<" ";
    }
    cout<<endl;
}
signed main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
}

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值