一些有意思的题


1.#10010. 「一本通 1.1 练习 6」糖果传递

题目
详解
AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=1e6+10;
int n;
int a[maxn],b[maxn];
void solve() {
	scanf("%d",&n);
	long long sum=0;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		sum+=a[i];
	}
	long long av=sum/n,num=0;
	for(int i=1;i<=n;i++)
		b[i]=a[i]-av+b[i-1];
	sort(b+1,b+1+n);
	for(int i=1;i<=n;i++)
		num+=abs(b[i]-b[n/2]);
	printf("%lld\n",num);
}
int main() {
	solve();
	return 0;
}

2.增加难度的抽签问题

抽签

将写有数字的N个纸片放入口袋中,你可以从口袋中抽取4次纸片,每次记下纸片的数字后都将其放回口袋中。编写一个程序,判断当纸片上所写的数字是k1,
k2, …, kn时,是否存在抽取4次和为m的方案。如果存在,输出Yes;否则, 输出No

在数据较小的情况下(ex:50),我们可以直接利用四重循环解决问题,50的4次方才1e6,完全莫得问题。但数据一大就不行了。比如n取1000,1000的4次方就1e12了,电脑说我不干了你找别脑吧/笑哭。此时我们就要优化算法了。
这里我们利用了强大的二分法,直接可以降到n2logn级别,换句话说,当n=1000时,复杂度才1e7,简直不要太精彩!
其实就是把内层的两个循环用二分法转化为logn级别了,另外注意数组的大小

//输入
int n, m, k[MAXN];
//保存2个数的和的数列
int kk[MAXN * MAXN];
bool binary_search(int x){
    //x的存在范围是kk[l], kk[l+1], ..., kk[r-1]
    int l = 0, r = n * n;
    //反复操作直到存在范围为空
    while(r - l >= 1){
        int i = (l + r) / 2;
        if(kk[i] == x) 
			return true; //找到x
        else 
			r = i;
    }
    //没找到x
    return false;
}
 
void solve(){
    //枚举k[c] + k[d]的和
    for(int c = 0; c < n; c++)    
        for(int d = 0; d < n; d++)       
            kk[c * n + d] = k[c] + k[d];

    //排序以便进行二分搜索
    sort(kk, kk + n * n);
    bool f = false;
    for(int a = 0; a < n; a++)   
        for(int b = 0; b < n; b++)        
            //将内侧的两个循环替换成二分搜索
            if(binary_search(m - k[a] - k[b]))      
                f = true;
    if(f) puts("Yes");
    else puts("No");
}

3. 区间查质数(大数也可)

查询区间内素数的个数
给定整数a和b,请问区间[a,b)内有多少个素数?
限制条件:
a<b<=1e12b-a<=1e6

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const long long  MAX_L = 2e6+10;
const long long  MAX_SQRT_B = 2e6+10;
bool is_prime[MAX_L];
bool is_prime_small[MAX_SQRT_B];

void segment_sieve(ll a,ll b){
	for(int i=0;(ll)i*i<b;i++)
		is_prime_small[i] = true;
	// a= 4   b= 7	
//		is_prime_small[0]=1;
//		is_prime_small[1]=1;
//		is_prime_small[2]=1;
		
	for(int i=0;i<b-a;i++)
		is_prime[i] = true;
		//b-a=3;
//		is_prime[0]=0;
//		is_prime[1]=1;
//		is_prime[2]=0;
		
	for(int i=2;(ll)i*i<b;i++){
		if(is_prime_small[i]){
			for(int j=2*i;(ll)j*j<b;j+=i)
				is_prime_small[j] = false;
			for(ll j=max(2ll,(a+i-1)/i)*i;j<b;j+=i)
				is_prime[j-a] = false;
		}
	}
}
int main(){
	ll a,b,sum=0;
	scanf("%lld %lld",&a,&b);
	segment_sieve(a, b);
	for(int i=0;i<b-a;i++)
	if(is_prime[i])
	sum++;
	printf("%lld\n",sum);	
	return 0;
} 

4.斐波那契的优化

int memo[MAX_N + 1];

int fib(int n){
	if(n<=1)
		return n;
	if(memo[n]!=0)
		return memo[n];
	return memo[n] = fib(n-1) + fib(n-2);
}

5.dfs实现全排列,字典序+去重

#include <bits/stdc++.h>
using namespace std;
const int N = 5e4+10;
typedef long long ll;
char s[10],t[10];
int book[10],l;
void dfs(int step){
	if(step == l){
		printf("%s\n",t);
		return ;
	}
	for(int i=0;i<l;i++){
		if(book[i])
			continue;
		book[i]=1;
		t[step]=s[i];
		dfs(step+1);
		book[i]=0;
		//删除重复数据 
		while(i < l-1 && s[i+1] == s[i])
			i++;
	}
}
int main(){
	scanf("%s",s);
	l = strlen(s);
	sort(s,s+l);
	dfs(0);
	return 0;
}

6.next_permuation实现全排列

#include <algorithm>
//即使有重复的元素也会生成所有的排列
//next_permutation是按照字典序来生成下一个排列的
int perm[MAX_N];
void permutation(int n){
	for(int i=0;i<n;i++)
		perm[i]=i;
	do{
		//对perm进行的操作 
	}while(next_permutation(perm,perm + n));
	//所有的排列生成后,next_permutation会返回false
	return ; 
}

7.天上的星星

题目

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 2e3+10;
int x,y,w,n,q,sum[M][M];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d %d %d",&x,&y,&w);
		sum[x+1][y+1] += w;
	}
	for(int i=1;i<=2001;i++)
		for(int j=1;j<=2001;j++)
			sum[i][j] += sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];
	
	scanf("%d",&q);
	while(q--){
		int x1,x2,y1,y2;
		scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
		printf("%d\n",sum[x2+1][y2+1]-sum[x2+1][y1]-sum[x1][y2+1]+sum[x1][y1]);
	}
	return 0;
}

8.结果填空:阶乘位数 计蒜客 - A2221

题目

在这里插入图片描述

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int main()
{
    double s=0;
    for(int i=1;; i++)
    {
        s+=log10(i);//斯特林公式判断阶乘位数核心代码
        if(int (s+1)>=10000)
        {
            cout<<i<<endl;
            break;
        }
    }
    return 0;
}


9.AcWing 105.七夕祭

题目
思路可参照糖果传递
AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
int C[N],R[N];
int n,m,t;
ll ans = 0;
ll check(int P[],int x){
	int S[N] = {0};
	ll sum = 0;
	ll average = t / x; 
	for(int i=1;i<=x;i++)
		S[i] = S[i-1] + P[i] - average; 
	sort(S+1,S+1+x);
	ll mid = S[(1 + x)/2];
	for(int i=1;i<=x;i++)
		sum += abs(S[i] - mid);
	return sum;
}
int main(){
	scanf("%d %d %d",&n,&m,&t);
	for(int i=1;i<=t;i++){
		int x,y;
		scanf("%d %d",&x,&y);
		R[x]++;
		C[y]++;
	}
	bool flag1,flag2;
	flag1 = flag2 = false;
	if(t % m == 0){
		flag1 = true;
		ans += check(C,m);
	}
	if(t % n == 0){
		flag2 = true;
		ans += check(R,n);
	}
	if(flag1 && flag2)
		printf("both %lld\n",ans);
	else if(flag1)
		printf("column %lld\n",ans);
	else if(flag2)
		printf("row %lld\n",ans);
	else 
		printf("impossible\n");
	return 0;
} 

10.AcWing 1351. 密码锁

题目

AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
string s,t;
int n;
int find(int v1,int v2){
	int res = 0,book[110]={0};
	book[v1]++,book[v2]++;
	for (int i = 1; i < 3; ++ i){
        if((v1 + i) % n == 0)
			book[n]++;
        else
			book[(v1 + i) % n]++;
        if((v1 - i + n) % n == 0) 
			book[n]++;
        else 
			book[(v1 - i + n) % n]++;
        if((v2 + i) % n == 0) 
			book[n]++;
        else 
			book[(v2 + i) % n] ++;
        if((v2 - i + n) % n == 0) 
			book[n]++;
        else 
			book[(v2 - i + n) % n]++;
	}
	for(int i=1;i<=n;i++)
		if(book[i] == 2)
			res++;
	return res;
}
int main(){
	int sum = 0;
	scanf("%d",&n);
	int a[5],b[5];
	scanf("%d %d %d",&a[1],&a[2],&a[3]);
	scanf("%d %d %d",&b[1],&b[2],&b[3]);
	if(n > 5){
		sum = 250;
		int mm = 1;
		for(int i=1;i<=3;i++)
			mm *= find(a[i],b[i]);
		sum -= mm;
	}
	else
		sum = n*n*n;
	printf("%d\n",sum);
	return 0;
} 

11.L2-4 哲哲打游戏 (25 分)

题目

AC代码:

#include<iostream>
#include<cstring>
#include<vector>
 
using namespace std;
 
const int N = 100010;
int n, m;
vector<int>g[N];
int record[N];
 
int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		int cnt;
		cin >> cnt;
		while (cnt--)
		{
			int x;
			cin >> x;
			g[i].push_back(x);
		}
	}
 
	int p = 1;
	while (m--)
	{
		int a, b;
		cin >> a >> b;
		if (a == 0)p = g[p][b - 1];
		else if (a == 1)
		{
			record[b] = p;
			cout << p << endl;
		}
		else
			p = record[b];
	}
 
	cout << p << endl;
 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值