可接受序列
【题目描述】
让计算机这样读入一列非负整数:
1、读入数T。
2、接着往下读入T个数。
3、如果数列读完了,则停止,否则,转到1。
但是,往往会出现这样的问题:执行第2步时,数列已经没有T个数了。如果这样,我们称这个数列是“不可接受的”,否则,称它是“可接受的”。我们需要用最少的步数把一个数列变成“可接受的”,一步是指:
1、把数列中的某一个数加1。
2、把数列中的某一个数减1。
【输入格式】
第一行有一个数N (1<=N<=1000000),表示数列的长度,接下来有n行,描述这个数列,每一行有一个非负整数(不超过1000000)。
【输出格式】
仅一个数,表示最少的步数。
【输入输出样例】
sequence.in |
sequence.out |
7 3 1 2 3 4 5 6 |
1 |
【数据规模】
对于50%的数据,N≤1,000;
对于80%的数据,N≤100,000;
对于100%的数据,N≤1,000,000。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> using namespace std; int n,a[1000010]; long long ans=9999999999; void dfs(int pos,long long cnt){ if(cnt>=ans)return; //if(pos>n)return; if(pos==n+1){ ans=min(ans,cnt); return; } if(pos==n){ dfs(pos+1,cnt+a[pos]); return; } for(int i=0;i+pos<=n+1;i++){ int step=abs(a[pos]-i); dfs(pos+i+1,cnt+step); } } int main(){ //freopen("Cola.txt","r",stdin); freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); dfs(1,0); cout<<ans; return 0; }
20分 暴力深搜
促销
【题目描述】
某某商场搞了一个促销活动,促销活动以以下方式进行:
- 一个想要参加活动的顾客将他的发票扔进抽奖箱里。
- 在每天的最后,从抽奖箱里抽出两张发票:
a) 金额最大的发票a
b) 金额最小的发票b
- 金额最大的发票的持有者得到a-b的奖金。
每天被抽出的发票都不会再被放回抽奖箱里。
你想知道促销活动结束时一共付出了多少奖金。
【输入格式】
第一行一个N,促销进行的天数;
接下来N行,第一个数是一个ki,表示第i天收到的发票数;接下来ki个数,每个数是一个发票的金额。
【输出格式】
一个数,整个促销活动过程中一共付出了多少奖金。
【输入输出样例】
promotion.in |
promotion.out |
5 3 1 2 3 2 1 1 4 10 5 5 1 0 1 2 |
19 |
【数据规模】
对于30%的数据,发票总数M不超过2000;
对于另外20%的数据,每张发票的金额不超过2000;
对于100%的数据,发票总数M不超过1000000,每张发票的金额不超过1000000。
#include<iostream> #include<cstdio> #include<queue> using namespace std; priority_queue<int>heap1; priority_queue<int>heap2; int n; long long ans; int main(){ //freopen("Cola.txt","r",stdin); freopen("promotion.in","r",stdin); freopen("promotion.out","w",stdout); scanf("%d",&n); int x,y; for(int i=1;i<=n;i++){ scanf("%d",&x); for(int j=1;j<=x;j++){ scanf("%d",&y); heap1.push(y); heap2.push(-y); } int a,b,a1,b1; a=heap1.top();heap1.pop(); b=heap2.top();heap2.pop(); if(a!=-b){ ans+=a+b; continue; } a1=heap1.top();heap1.pop(); b1=heap2.top();heap2.pop(); if(a+b1>b+a1){ heap1.push(a1); heap2.push(b); ans+=a+b1; continue; } else { heap1.push(a); heap2.push(b1); ans+=a1+b; continue; } } cout<<ans; return 0; }
100分 两个堆
亲和数
【题目描述】
某一天,老徐看了一本趣味数学书,上面提到了亲和数:定义数对 (x,y) 为亲和数对当且仅仅当x、y为不同正整数,且x、y各自的所有非自身正因子之和等于另一个数。例如 (220,284) 和 (284,220) 都是亲和数对,因为:220的所有非自身正因子之和为:1 + 2 + 4 + 5 + 10 + 11 + 20 + 22 + 44 + 55 + 110 = 284。284的所有非自身正因子之和为:1 + 2 + 4 + 71 + 142 = 220
数对 (x,y ) 跟 (y,x) 被认为是同一数对,所以我们只考虑 x<y 的情况。
老徐对某个范围内的亲和数对的数量非常感兴趣,所以希望你能帮她编写一个程序计算给定范围内的亲和数对的数量。给定一个范围A到B,如果A≤ x ≤ B,则我们称 (x,y)在范围[A,B]内。
【输入格式】
从文件的第一行分别读入正整数A和B,其中A、B满足
1 ≤ A ≤ B ≤ 108 且 B-A ≤ 105
【输出格式】
输出文件只有一行,就是[A,B]内亲和数对的数量
【输入输出样例】
amicable.in |
amicable.out |
200 1200 |
2 |
注:[200,1200] 内的数对只有两个,分别是(220,284)和(1184 1210)
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int a,b,bit[10],len,q[10]; bool pan(int num){ int sum=1; for(int i=2;i*i<=num;i++){ if(num%i==0&&i*i!=num)sum+=i+num/i; if(i*i==num)sum+=i; } if(sum<=num)return 0; for(int i=2;i*i<=sum;i++){ if(sum%i==0&&i*i!=sum)num-=i+sum/i; if(i*i==sum)num-=i; if(num<0)return 0; } if(num==1)return 1; } int shu(int pos,int num,bool limit){ if(pos==len+1){ if(pan(num))return 1; return 0; } int end=limit?bit[pos]:9; int ans=0; for(int i=0;i<=end;i++){ ans+=shu(pos+1,num*10+i,limit&&i==end); } return ans; } int dp(int x){ memset(q,0,sizeof(q)); memset(bit,0,sizeof(bit)); len=0; while(x){ q[++len]=x%10; x/=10; } for(int i=len,j=1;i>=1;i--,j++)bit[i]=q[j]; return shu(1,0,1); } int main(){ //freopen("Cola.txt","r",stdin); freopen("amicable.in","r",stdin); freopen("amicable.out","w",stdout); scanf("%d%d",&a,&b); cout<<dp(b)-dp(a-1); return 0; }
50分 数位dp(记忆化没写成)