[泉州4月月赛]

开始被毒瘤数据卡了几个点,没有一下\(AK\)

\(A\)
考虑答案为\(n - \lfloor n / x \rfloor\)

A
#include<iostream>
#include<cstdio>
#define ll long long

inline ll abs(ll x){
  return (x < 0) ? -x : x;
}

int main(){
  ll n,x;
  scanf("%lld%lld",&n,&x);
  if(x == 0)
  puts("0");
  else
  std::cout<<n - n / abs(x)<<std::endl;
}

\(B\)

倒序算就行了。

B
#include<iostream>
#include<cstdio>
#define ll long long
#define N 1000005
ll c[N];
int main(){
  ll n,k;
  scanf("%lld%lld",&n,&k);
  for(int i = 1;i <= n;++i){
  	scanf("%lld",&c[i]);
  }
  for(int i = n;i >= 1;--i){
  	k -= c[i];
  	if(k <= 0){
  		std::cout<<i<<std::endl;
  		return 0;
  	}
  }
}  

\(C\)

感性理解一下,答案是\(\sum_{x1}^{y1}a_i\sum_{x2}^{y2}b_i\)
前缀和维护就好了

C
#include<iostream>
#include<cstdio>
#define ll long long
#define N 1000005

ll n,m;

ll suma[N],sumb[N];

int main(){
	scanf("%lld%lld",&n,&m);
	for(int i = 1;i <= n;++i){
		ll x;
		scanf("%lld",&x);
		suma[i] = suma[i - 1] + x;
	}
	for(int i = 1;i <= m;++i){
		ll x;
		scanf("%lld",&x);
		sumb[i] = sumb[i - 1] + x;
	}
	ll k;
	scanf("%lld",&k);
	while(k -- ){
		ll x1,x2,y1,y2;
		scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
		std::cout<<(suma[x2] - suma[x1 - 1]) * (sumb[y2] - sumb[y1 - 1])<<std::endl;
	}
}

\(D\)
对于非负数,直接输出他的整数部分。
对于负数,如果小数部分是\(.000\)或者是整数,直接输出,否则把整数部位\(-1\)

D
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long 
#define N 10000005

char s[N];
ll p = 0,k = 0;
ll num[N];

int main(){
	scanf("%s",s + 1);
	for(int i = 1;i <= strlen(s + 1);++i)
	if(s[i] == '.')
	p = i;
	if(!p)
	std::cout<<s + 1;
	else{
		if(s[1] != '-'){
		for(int i = 1;i <= strlen(s + 1);++i){
		if(s[i] != '.')
		std::cout<<s[i];
		else
		break;
		}
		}else{
			for(int i = p + 1;i <= strlen(s + 1);++i)
			if(s[i] != '0')
			k = i;
			if(k){
			ll pr = 0;
			for(int i = 2;i < p;++i)
			num[i - 1] = s[i] - '0';
			num[p - 2] += 1;
			pr = num[p - 2] / 10;
			num[p - 2] = num[p - 2] % 10; 
			for(int i = p - 3;i >= 1;--i){
				num[i] += pr;
				pr = num[i] / 10;
				num[i] = num[i] % 10;
			}
			std::cout<<"-";
			if(pr)
			std::cout<<pr;
			for(int i = 1;i <= p - 2;++i)
			std::cout<<num[i];
			}else{
				for(int i = 1;i < p;++i)
				std::cout<<s[i];
			}
		}
	}
}

\(E\)
我们发现我们只要对一堆的答案确定,那么可以计算出总答案。
我们用可达性\(01\)背包,算出有哪些值可以平凑出来就好。
注意有负值,所以考虑全部数向上移。
注意不要越界。

E
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#define ll long long 
#define N 2005

ll n;
ll num[N],sum,ans,maxx,minn;
bool QWQ[N * 2000];

int main(){
	scanf("%lld",&n);
	for(int i = 1;i <= n;++i){
		scanf("%lld",&num[i]),sum += num[i];
		if(num[i] > 0)
		maxx += num[i];
		else
		minn -= num[i];
	}
	QWQ[minn + 1000] = 1;
	for(int i = 1;i <= n;++i){
		for(int s = maxx + minn + 1000;s >= -2 * minn;--s){
			if(s + num[i] + minn + 1000 >= 0)
			if(!QWQ[s + num[i] + minn + 1000] && QWQ[s + minn + 1000]){
				QWQ[s + num[i] + minn + 1000] = QWQ[s + minn + 1000];
				ans = std::max(ans,(s + num[i]) * (sum - s - num[i]));
			}
		}
	}
	std::cout<<ans<<std::endl;
}

\(F\)
因为是连续的一串数字。
所以我们只要考虑一个数字就好。
对于一个数字处理出他在哪里出现过。
那么让两个相同数字的位置相邻的代价是消除两个位置中所有的数字。
维护一下消除代价的前缀和,那么对于一个位置,他的答案是最大的到他位置的代价小于\(k\)的长度。
指针维护一下。
复杂度\(O(n)\)
考虑分析,每个数字只会走一遍。

F
#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long
#define N 200005

ll n,m,k;

std::vector<int>QWQ[N];
ll sum[N],ans = 1;

int main(){
	scanf("%lld%lld%lld",&n,&m,&k);
	for(int i = 1;i <= n;++i){
		ll x;
		scanf("%lld",&x);
		QWQ[x].push_back(i); 
	}	
	for(int i = 1;i <= m;++i){
		for(int j = 1;j <= QWQ[i].size();++j)
		sum[j] = 0;
		for(int j = 0;j < QWQ[i].size();++j){
			sum[j + 1] = sum[j] + QWQ[i][j + 1] - QWQ[i][j] - 1; 
		}
		ll l = 0;
		for(int j = 1;j < QWQ[i].size();++j){
			while(sum[j] - sum[l] > k)
			l ++ ;
			ans = std::max(ans,j - l + 1);
		}
	}
	std::cout<<ans<<std::endl;
}
posted @ 2021-04-18 17:57  fhq_treap  阅读(127)  评论(0编辑  收藏  举报