文章目录
1.#10010. 「一本通 1.1 练习 6」糖果传递
#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;
}