CF-927(已更新:B C E)

CF-927

依旧……难绷……

E代码先放这,刚CF开了去交了下过了,……下午有比赛,之后再更新思路-^-

B

分析

  • 第i个征兆出现在第i-1个征兆之后(不能再同一年出现)
  • 第i个征兆只会出现在a[i]的整数倍年份(题上说每a[i]年出现一个征兆)

也就是说,我们要通过把a[i]变成它的倍数的方式使a[i]>a[i-1],使数组递增,这样每个a[i]才是第i个征兆出现的年份,这样以后第a[n]年所有征兆都会出现,也即我们要求的答案

操作

本题的重点就在于如何高效的实现“把a[i]变成它的倍数的方式使a[i]>a[i-1]”。

遍历求倍数会t,赛后会被hack掉-^-

那我们怎么才知道a[i]该变成它自身的几倍数呢?显然要看a[i-1],不妨想几个例子,如3 2,其中2要变成4,即2乘2,再如5 2,2要变成6,即2乘3,所以这个要乘的倍数就是k=(a[i-1]/a[i]+1),那a[i]=a[i]乘k,由于我们要求的只是a[n],可以设ans初值为a[1],在2~n的循环里跑ans=a[i]*(ans/a[i]+1),最后得到的ans即为a[n]——a[i-1]<a[i]时a[i-1]/a[i]=0,也是成立的。

解释一下这个递推式:实际上是a[i]=(a[i-1]/a[i]+1) a[i]的更新来自当前的a[i]与它的上一个状态,即a[i-1]。左式的ans相当于更新后的a[i],右边的a[i]是原本的a[i],右边的ans还未被更新,所以还等于当前的a[i-1]

代码

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int N=2e5+5;
int a[N];
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
	int t,n,x,cnt=0,ans=0;cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		ans=a[1];
		for(int i=2;i<=n;i++){
			ans=a[i]*(1+ans/a[i]);
		}
		cout<<ans<<endl;
	}
	return 0;
}

C

分析

不能直接求积作除——关键在于除法的模运算要用到逆元,而m又不一定为质数。所以应该考虑不用除法运算的方法。

操作

  1. 可以用线段树维护区间积,读入指令相当与查询的左右边界移动
  2. 题中的操作我们可以理解成按指令顺序把乘积除以删掉的数再取模输出,那反过来想,输出的反向顺序是不是就是把1乘上倒序的删数顺序的数再取模输出?

4 6
3 1 4 2
LRRL
删数顺序:3 2 4 1
其倒序为:1 4 2 3
输出的倒序为:1 4(1*4%6) 2(1*4*2%6) 0(1*4*2*3%6) 

代码

线段树做法

用区间和的板子改的……

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define endl '\n'
#define int long long
#define debug(x) cout<<x<<" "<<endl;
#define _debug(a,n) for(int i=0;i<n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a, b) memset(a, b, sizeof(a))
#define lc p<<1
#define rc p<<1|1
const int N=2e5+5;
int a[N],n,m;
struct tree{
	int l,r,sum;
}tr[N<<2];
void pushup(int p){
	tr[p].sum=(tr[lc].sum%m*tr[rc].sum%m)%m;
}
void build(int p,int l,int r){	
	tr[p]={l,r,a[l]};
	if(l==r) return; 
	int mid=l+r>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	pushup(p);
}
int query(int p,int x,int y){ 
	if(x<=tr[p].l&&y>=tr[p].r){
		return tr[p].sum%m;
	}	
	int mid=tr[p].l+tr[p].r>>1;
	int sum=1;
	if(x<=mid) sum*=query(lc,x,y)%m;
	if(y>mid) sum*=query(rc,x,y)%m;
	sum%=m;
	return sum;
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
	int x,y,op,k,t;cin>>t;
	while(t--){
		cin>>n>>m;
		for(int i=1;i<=n;i++) cin>>a[i];	
		string s;cin>>s;
		build(1,1,n);
		x=1,y=n;	
		for(auto i:s){
			cout<<query(1,x,y)<<" ";
			if(i=='L') x++;			
			else y--;
		}		
		cout<<endl;
	}

    return 0;
}






倒序做法

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
	int t,n,x,m,cnt=0,ans=0;cin>>t;
	while(t--){
		cin>>n>>m;
		deque<int>q,tmp,out;
		rep(i,1,n){
			cin>>x;
			q.push_back(x);
		}
		string s;cin>>s;
		for(auto i:s){
			if(i=='R'){
				tmp.push_back(q.back());
				q.pop_back();
			}
			else{
				tmp.push_back(q.front());
				q.pop_front();
			}
		}
//		for(auto i:tmp) cout<<i<<" ";
		reverse(tmp.begin(),tmp.end());
		int e=1;
		for(auto i:tmp){
			e*=i;
			e%=m;
			out.push_front(e);
		}
		for(auto i:out){
			cout<<i<<" ";
		}
		cout<<endl;
	}
	return 0;
}

E

分析

就是说答案等于每一位的变化,而这是有规律的,我们联想它的过程——12->0答案为13,其中10->9(09),两位数都变化了,对答案的贡献为2,结果就是个位数变化了12次,十位数变化了1次,因此可以推出答案为各个数位的前缀之和

如12345—>12345+1234+123+12+1=13715

操作

即如何高效的求解“12345—>12345+1234+123+12+1=13715”这一过程,我们把这个式子按数位对齐可以发现,结果数字的个位等于个位到万位的数字加起来再进位,十位等于十位到万位的数字加起来之和再进位,也即每位的数是高位到低位的数的前缀和,于是我们可以用数组存下这个前缀和,再做进位处理

如
1 2 3 4 5
  1 2 3 4
    1 2 3
      1 2
        1
1 3 6 10 15//可以看出每位的数是高位到低位的数的前缀和
进位后得:
13715    

进位处理的几个要点:

  • 最高位+1的位数有数的话要使数组长+1
  • 注意删去前导零

代码

注释版

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=0;i<n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
	int t,n,x,cnt=0;cin>>t;
	string s;
	while(t--){
		cin>>n>>s;
		vector<int>a(n+5);
		a[0]=s[0]-'0';
		for(int i=1,l=1;i<n;i++,l++){
			a[l]=a[l-1]+s[i]-'0';				
		}
        //翻转,最高位i=n-1,可以进位到i=n
		reverse(a.begin(),a.begin()+n);
		for(int i=0;i<n;i++){//进位处理
			if(a[i]>9){
				a[i+1]+=a[i]/10;
				a[i]%=10;						
			}
		}
		if(a[n]) n++;//如果第n+1位,要使数组长度+1,避免95+5得00
		reverse(a.begin(),a.begin()+n);
		string ans;
		for(int i=0;i<n;i++){
			ans+=a[i]+'0';
		}
        //删去前导零
		int i=0;
		while(ans[i]=='0') i++;
		ans.erase(0,i);
		cout<<ans<<endl;
	}
	return 0;
}
posted @ 2024-02-19 00:42  mono_4  阅读(18)  评论(0编辑  收藏  举报