A: M个素数
题目描述
小米最近在研究素数。
他希望能够快速得到一个指定的正整数N后面的M个素数(不包含N),你能否编写一个程序帮帮他?
输入
单组输入。
输入两个正整数N和M,N<=10^6,M<=10 ^3。
N和M之间用空格隔开。
输出
输出正整数N后面的M个素数(如果N是一个素数的话,并不包含N)。
- 枚举判断
- 比较水(这里用的六素数法)
#include <bits/stdc++.h>
using namespace std;
bool prime(int n){
if(n==2||n==3)return 1;
else if(n%6!=1&&n%6!=5)return 0;
else {
for(int j=5;j<=(int)sqrt(n);j+=6)
if(n%j==0||n%(j+2)==0)return 0;
return 1;
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
if(n&1)n+=2;
else n++;
for(int i=1;i<=m;i++){
while(!prime(n)){
n+=2;
}
printf("%d%c",n,i==m ? '\n':' ');
n+=2;
}
return 0;
}
B: 容易等级
题目描述
小米的英语老师是一个非常有趣的人。每一次考试之前她都会在不经意间透露一下试题的难度,她会在黑板上写一串长长的字符。你需要从这串字符中按照次序找到E或e、A或a、S或s、Y或y这四个字母,每四个字母为一组,将构成一个大家熟悉的单词(easy)。每找到一组字母,即构成一个单词easy则容易等级加1。当然,容易等级越大就意味着考试题目越容易,所以小米希望能够从中找到最多的字母组合。值得注意的是如果有多于一个easy,每一个easy都需要按照次序出现,也就是说下一个easy中的“e”必须在前一个easy中的“y”之后出现。
你能否编写一个程序告诉小米这次英语考试的容易等级是多少呢?
输入
单组输入。输入一个长度为n的字符串,n<=1000。
输出
输出一个非负整数表示此次英语考试的容易等级。
- 简单模拟
- 从‘e’或‘E’开始一直找到‘y’或‘Y’才算一个,然后重新开始找
#include<bits/stdc++.h>
using namespace std;
#define ll long long
string s;
string s1="easy";
string s2="EASY";
int main(){
cin>>s;
int ans=0;
int pos=0;
for(int i=0;i<s.size();i++){
if(s[i]==s1[pos]||s[i]==s2[pos]){
pos++;
if(pos==4){
ans++;
pos=0;
}
}
}
cout<<ans<<endl;
return 0;
}
C: 完美串
题目描述
完美串的定义如下:
在一个仅由小写英文字母组成的字符串中,如果其中每一个字母出现的次数都相同则称为完美串。
现在允许你对一个字符串进行若干次删除或者插入操作将其变成一个完美串。每增加一个字母或者删除一个字母都记为1次操作,例如对于字符串“abbccc”而言,可以通过增加一个“a”和删除一个“c”将其变成一个完美串,操作次数为2。不难看出,这也是将“abbccc”变成完美串所需的最少操作次数。
请编写一个程序计算最少需要进行多少次操作才能实现一个输入字符串到完美串的转变。
输入
单组输入。
输入一个长度为n的仅由小写英文字母组成的字符串,保证n为不同字符数的倍数。n<=10^6。
输出
输出一个非负整数,表示将输入字符串变成一个完美串所需的最少操作次数。
- 思维题
- 每个字符数量与平均个数(字符总数除字符种类)差之和
#include <bits/stdc++.h>
using namespace std;
int a[30];
int ans;
int main(){
string s;
cin>>s;
int n=s.size(),m=0;
for(int i=0;i<n;i++){
if(!a[s[i]-'a'])m++;
a[s[i]-'a']++;
}
n/=m;
for(int i=0;i<26;i++)
if(a[i])ans+=abs(a[i]-n);
cout<<ans<<endl;
return 0;
}
D: 公平分配
题目描述
热情的X星人和友好的地球人一起联手发现了一堆千年宝藏。大家一起对这堆宝藏中的每一件宝贝进行了估值,每件宝贝的估值都是一个正整数,一共有n件宝贝。已知每一件宝贝都是独一无二的,且都不可分割。当然,可能存在某些宝贝的估值相等。
为了体现公平性,X星人和地球人决定按照估值来平分宝藏,要求X星人和地球人所分得的宝贝的估值之和相等。
现在给出这n件宝贝的估值,你能否编写一个程序计算出有多少种公平分配的方案?
如果不存在公平分配方案,则输出“No solution!”。
输入
单组输入。
第1行输入一个正整数n,表示宝贝的总数量。(n<=10^3)
第2行输入n个正整数,分别表示每一件宝贝的估值。两两之间用空格隔开。
输出
输出公平分配的方案总数,结果对1e9+7取模。如果不存在公平分配方案,输出“No solution!”。
- 动态规划
- 容易看出和如果为奇数就No solution!,否则就DP
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define MOD 1000000007
int n;
ll sum;
int a[1005];
ll dp[1000005];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
}
if(sum&1)puts("No solution!");
else{
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=sum/2;j>=a[i];j--){
dp[j]=(dp[j]+dp[j-a[i]])%MOD;
}
}
printf("%lld\n",dp[sum/2]);
}
return 0;
}
E: 倍数
题目描述
现在给你N个正整数,从中选取3个数字的和,刚好能够组成M的倍数。请问存在多少种不同的选取方案?
相同的一组数如果次序不同只能算做一种方案,不同位置的相同数字需当做同一个数字看待。例如一组数字[2,3,3,4],从中选取3个数字的和来组成3的倍数,只存在一种方案(2,3,4)。
输入
单组数据。
第1行输入两个正整数N和M,N<=20。
第2行输入N个正整数,两两之间用空格隔开。
输出
输出不同的选取方案的数量。
- 搜索
- 还是比较简单的搜索,注意判重就行
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
int ans;
map<string,bool>vis;
int a[25];
void dfs(int num,int pos,int sum,string s){
if(num==3){
if(!vis[s]){
if(sum%m==0)
ans++;
vis[s]=1;
}
return ;
}
if(pos>n)return ;
dfs(num,pos+1,sum,s);
dfs(num+1,pos+1,sum+a[pos],s+" "+to_string(a[pos]));
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+1+n);
dfs(0,1,0,"");
printf("%d\n",ans);
return 0;
}
F: 对战卡
题目描述
小明最近迷上了一款基于对战卡的游戏,该游戏的规则如下:
每位玩家都拥有N张对战卡和一张可以摆放M张卡片的对战图。每一张对战卡上都标有一个正整数用于表示该卡片上角色的攻击值,不同的对战卡其攻击值不一定相等。
玩家可以从N张对战卡中选取若干张摆放到对战图上,在对战图上一共有M个可以摆放的位置。然后计算对战图的攻击值,即摆放在一张对战图上的所有对战卡的攻击值之和。
小明希望能够快速得到一张攻击值最大的对战图,你能否编写一个程序帮帮他?
输入
单组输入,每组包含两行。
第1行两个正整数N和M,N为小明拥有的对战卡数量,M为对战图上可以摆放的对战卡数量。(1< N<=105且1<M<=105)
第2行包含N个正整数,分别表示N张对战卡的攻击值,两两之间用空格隔开。
输出
输出小明的对战图能够具有的最大攻击值。
- 签到题
- 输出前m个最大的数之和就行,注意范围m可能大于n
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
int a[100005];
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
ll ans=0;
sort(a,a+n);
reverse(a,a+n);
for(int i=0;i<m&&i<n;i++)
ans+=a[i];
printf("%lld\n",ans);
return 0;
}
G:a碟喜欢的饮料
题目描述
a碟最近看上了一款饮料,这个饮料最近在搞活动,每一瓶饮料都有一个编号,这个活动的头等奖的要求是
- 给定一个饮料编号为x(-10^7 < = x < = 10 ^7),你必须买包含的x区间[L,R]中的饮料
- 这个区间中的编号必须全选
- 该区间中所有编号的和必须是一个质数,而且你要使得选择的饮料数量最少 a碟通过关系,进入了饮料的仓库,也就是说他可以买到任意编号的饮料。他想拿到头等奖,但是他却对这个要求犯了难。你能够编写程序,帮助a碟拿到头等奖吗?如果能买到对应的饮料符合要求,输出购买的最少的饮料数量。如果无法获得头奖,那么输出-1。
输入
第一行包含一个整数T测试用例的数量。然后是T组测试用例。 每个测试用例的第一行也是唯一一行包含一个整数x同要求中的。
输出
对于每个测试用例,如果存在这样的饮料,您需要输出购买的最少的饮料数量,否则输出−1。
- 比较难的思维题
- 素数预处理,再分小于等于0、大于0两种情况分析
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e7+5;
int n;
int ans;
bool pr[N],vis[N];
void Init_prime(){//筛法求素数
for(int i=2;i<N;i++){
if(!vis[i])pr[i]=1;
for(int j=2*i;j<N;j+=i){
vis[j]=1;
}
}
}
int main(){
int t;
scanf("%d",&t);
Init_prime();
while(t--){
scanf("%d",&n);
ans=0;
if(n<=0){
ans=2*abs(n)+1;
n=abs(n)+1;
while(!pr[n]&&!pr[2*n+1]){
ans+=2;
n++;
}
if(pr[n])ans++;
else ans+=2;
}
else {
ans=0;
while(!pr[n]&&!pr[2*n-1]&&!pr[2*n+1]){
ans=2*abs(n)+1;
n++;
}
if(pr[n])ans++;
else ans+=2;
}
printf("%d\n",ans);
}
return 0;
}
H: X星人的趣味运动会
题目描述
一年一度的X星趣味运动会即将在X星体育馆隆重举行。本届趣味运动会一共有N个项目,有M个X星人报名参赛,且每个X星人的参赛项目总数不能超过5项。
由于趣味运动会都是团体赛,一旦某个人报名参与某一项比赛就必须全程在该项比赛的赛场。
如果一个人报名了两项比赛,那么这两项比赛不能够安排在同一场次,同时每个项目只能出现在一场比赛中。
假设每一项比赛的总时间都是相同的。X星趣味运动会组委会希望通过对报名情况进行分析,来确定最少需要安排多少场比赛才可以让所有的项目都顺利完成。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=2e4+5;
int mp[110][110]; //mp[i][j]:表示i,j项目不能在同一场次
vector<int>num[110]; //num[i]:表示i场次有多少项目
int n,m,ans=inf;
void dfs(int now,int cnt){ //当前遍历的项目为now,目前已经安排cnt个场次
if(cnt>=ans)return ;
if(now>n){
ans=min(ans,cnt);
return ;
}
for(int i=1;i<=cnt;i++){
int flag=1;
int siz=num[i].size();
for(int j=0;j<siz;j++){
if(mp[now][num[i][j]]==1){
flag=0;break;
}
}
if(flag){
num[i].push_back(now);
dfs(now+1,cnt);
num[i].pop_back();
}
}
num[++cnt].push_back(now);
dfs(now+1,cnt);
num[cnt].pop_back();
}
int main(){
scanf("%d%d",&n,&m);
memset(mp,0,sizeof(mp));
int x;
for(int i=1;i<=m;i++){
vector<int>ve;
while(~scanf("%d",&x)){
for(int j=0;j<ve.size();j++){
mp[ve[j]][x]=mp[x][ve[j]]=1;
}
ve.push_back(x);
if(getchar()!=' ') break;
}
}
dfs(1,0);
printf("%d\n",ans);
return 0;
}
I:a碟的Java
题目描述
a碟最近无聊,看了看java,他重新看到了String的字符串常量池的使用,对其产生了浓厚的兴趣
【字符串常量池(String pool, String intern pool, String保留池)】 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。
字符串常量池这么好用,那么会不会满呢?a碟一直在思考这个问题(此题目我们假设溢出的处理如下方的过程所述)
假设字符串常量池中有 M 个单元,每单元能存放一个字符串。每将一个新字符串存入字符串常量池前,如果当前字符串常量池中有该字符串,那么直接取出来使用,不需要重新存入到字符串常量池;如果当前字符串常量池中已存入的字符串不超过 M-1,会将新字符串存入一个未使用的字符串常量池单元;若字符串常量池中已存入 M 个字符串,字符串常量池会清空最早进入字符串常量池的那个字符串,腾出单元来,存放新字符串。
a碟突发奇想,假设他想要在字符串常量池中查N个字符串(假设他能查),如果查不到,则将该字符串存入字符串常量池,那么需要存入多少次?假设在初始阶段,字符串常量池中没有任何字符串。
输入
共 2行。每行中两个数之间用一个空格隔开。
第一行为两个正整数M,N,代表字符串常量池的容量和查的字符串个数 (1<=M<=100,1<=N<=1000)
第二行为N个非负整数,每个数(大小不超过 10001000)代表一个字符串。两个字符串是同一个字符串,当且仅当它们对应的非负整数相同。
输出
一个整数,为需要存入字符串的次数。
- 模拟
- 队列直接模拟就行
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
int ans;
int a[1005];
queue<int>q;
bool Find(int num){
queue<int>k;
k=q;
while(!k.empty()){
if(k.front()==num)
return 1;
k.pop();
}
return 0;
}
int main(){
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(!Find(a[i])){
ans++;
q.push(a[i]);
if(q.size()>m){
q.pop();
}
}
}
printf("%d\n",ans);
return 0;
}