目录
P1217 [USACO1.5] 回文质数 Prime Palindromes
P2241 统计方形(数据加强版)
题目描述
有一个×m 方格的棋盘,求其方格包含多少正方形、长方形(不包含正方形)。
输入格式
一行,两个正整数n,m(n≤5000,m≤5000)。
输出格式
一行,两个正整数,分别表示方格包含多少正方形、长方形(不包含正方形)。
输入样例
2 3
输出样例
8 10
题解
一、正方形个数
1.固定正方形的右下角(i,j)
2.此时正方形的个数为Min(i,j).
3.枚举右下角,求和即可。
二、长方形个数
1.矩形个数-正方形个数.
2.固定矩形右下角(i,j)
3.此时矩形个数为i*j,求和即可.
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
long long n,m,sum,sum1;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
sum+=min(i,j);
sum1+=i*j;
}
}
cout<<sum<<" "<<sum1-sum<<endl;
return 0;
}
P1036 [NOIP2002 普及组] 选数
题目描述
已知 n 个整数1,2,⋯ ,x1,x2,⋯,xn以及1个整数 k(k<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当n=4,k=3,4个整数分别为3,7,12,19时,可得全部的组合与它们的和为:
3+7+12=22
3+7+19=29
7+12+19=38
3+12+19=34
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=29。
输入格式
第一行两个空格隔开的整数n,k(1≤n≤2,k<n)。
第二行n个整数,分别为x1,x2,⋯,xn(1≤xi≤5×1e6)。
输出格式
输出一个整数,表示种类数。
输入样例
4 3
3 7 12 19
输出样例
1
题解
#include<iostream>
using namespace std;
int n,k,num;
int a[25];
//判断素数
bool isprime(int a)
{
for(int i=2;i*i<a;i++)
{
if(a%i==0) return false;
}
return true;
}
//递归
void res(int start,int count,int sum)
{
//start:开始选数的位置
//count:已经选了几个数
//sum: 目前所选数之和
int i;
if(count==k && isprime(sum))
{
num++;
//判断所选的k个数之和是否为素数
//num统计符合条件的和的个数
}
for(int i=start;i<=n;i++)
{
res(i+1,count+1,sum+a[i]);
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
res(1,0,0);//从第一个数开始搜索,找到0个数,目前和为0
cout<<num<<endl;
return 0;
}
P1157 组合的输出
题目描述
排列与组合是常用的数学方法,其中组合就是从 n 个元素中抽出 r 个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取 r 个数。
现要求你输出所有组合。
例如n=5,r=3,所有组合为:123,124,125,134,135,145,234,235,245,345。
输入格式
一行两个自然数 n,r(1<n<21,0≤r≤n)。
输出格式
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
注意哦!输出时,每个数字需要 33 个场宽。以 C++ 为例,你可以使用下列代码:
cout << setw(3) << x;
输出占3个场宽的数x。注意你需要头文件 iomanip
。
输入样例
5 3
输出样例
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
next_permutation函数
头文件:<algorithm>
作用:列举数字所有排列方式
生成给定序列的下一个较大排序,直到序列按降序排列为止。到这里还需要强调的一点是,如果你希望生成所有的排列方式,一定要先将序列按升序排列,这里可以与sort函数结合起来使用,先用sort升序排列,再调用next_permutation函数。
#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;
int a[25];//a[i]代表是否选第i个数,0选,1不选
int n,r;
int main()
{
cin>>n>>r;
for(int i=r+1;i<=n;i++) a[i]=1;//不选的数赋初值
do//使用while会跳过1,2,3这种最开始的排列情况。
{
for(int i=1;i<=n;i++)
if(a[i]==0) cout<<setw(3)<<i;//如果是0就输出,注意三个常宽
cout<<endl;//换行
}while(next_permutation(a+1,a+1+n));
return 0;
}
P3392 涂国旗
题目描述
某国法律规定,只要一个由N×M个小方块组成的旗帜符合如下规则,就是合法的国旗。
- 从最上方若干行(至少一行)的格子全部是白色的;
- 接下来若干行(至少一行)的格子全部是蓝色的;
- 剩下的行(至少一行)全部是红色的;
现有一个棋盘状的布,分成了 N 行 M 列的格子,每个格子是白色蓝色红色之一,小 a 希望把这个布改成该国国旗,方法是在一些格子上涂颜料,盖住之前的颜色。
小a很懒,希望涂最少的格子,使这块布成为一个合法的国旗。
输入格式
第一行是两个整数N,M。
接下来N行是一个矩阵,矩阵的每一个小方块是W
(白),B
(蓝),R
(红)中的一个。
输出格式
一个整数,表示至少需要涂多少块。
输入样例
4 5
WRWRW
BWRWB
WRWRW
RWBWR
输入样例
11
样例说明
目标状态是:
WWWWW
BBBBB
RRRRR
RRRRR
一共需要改11个格子。
数据范围
对于100%的数据,N,M≤50。
struct是用来定义一个结构体类型的关键字。结构体是一种用户自定义的数据类型,可以包含不同类型的数据成员,这些成员可以被同时访问,例如:
struct Person { string name; int age; };
void是用来表示函数的返回类型的关键字。当一个函数不返回任何数值时,可以将其返回类型声明为"void"。例如:
void doSomething() { // 函数体 }
inline是用来告诉编译器将函数的代码直接插入到调用代码中,而不是通过函数调用的方式来执行。这样可以减少函数调用的开销,提高程序的执行效率。在C++中,可以通过在函数声明或定义前面加上"inline"关键字来指示编译器将该函数作为inline函数处理。例如:
inline int add(int a, int b) { return a + b; }
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int sum=0x7fffffff;//定义sum为无穷大
int w[55],b[55],r[55];//w,b,r分别存储前几行需要修改的颜色
string s;//以字符串形式输入每行,避免二维字符数组超时
inline int check(char c)//定义函数,查找每行需要修改对应的颜色c
{
int tot=0;
for(int i=0;i<m;i++)
{
if(s[i]!=c) tot++;
}
return tot;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s;
w[i]=w[i-1]+check('W');
b[i]=b[i-1]+check('B');
r[i]=r[i-1]+check('R');
}
for(int i=1;i<n-1;i++)
{
for(int j=1+i;j<n;j++)//根据题目条件,w\b\r至少一行,所以不取=
{
sum=min(sum,w[i]+b[j]-b[i]+r[n]-r[j]);
}
}
cout<<sum;
return 0;
}
P1217 [USACO1.5] 回文质数 Prime Palindromes
题目描述
因为 151151 既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 151151 是回文质数。
写一个程序来找出范围[a,b](5≤a<b≤100,000,000)(一亿)间的所有回文质数。
输入格式
第一行输入两个正整数 a 和 b。
输出格式
输出一个回文质数的列表,一行一个。
输入样例
5 500
输出样例
5
7
11
101
131
151
181
191
313
353
373
383
说明/提示
提示 1: 找出所有的回文数再判断它们是不是质数(素数)。
提示 2: 要产生正确的回文数,你可能需要几个像下面这样的循环。
//产生长度为5的回文数
for (d1 = 1; d1 <= 9; d1+=2) { // 只有奇数才会是素数
for (d2 = 0; d2 <= 9; d2++) {
for (d3 = 0; d3 <= 9; d3++) {
palindrome = 10000*d1 + 1000*d2 +100*d3 + 10*d2 + d1;//(处理回文数...)
}
}
}
题解
1.回文数少,所以先判断回文,再判断质数(顺序错误会超时)
2.偶数位的回文数(除了11)必然不是质数
#include<iostream>
using namespace std;
int l,r;
bool check1(int x)//判断位数
{
if((10<=x&&x<=100&&x!=11)||(1000<=x&&x<=10000)) return 0;
if((100000<=x&&x<=1000000)||(10000000<=x&&x<=100000000)) return 0;
return 1;
}
bool check2(int x)//判断回文
{
int a[20],flag=1;
while(x>0)
{
a[flag]=x%10;
x/=10;
flag++;
}
for(int i=1;i<=flag/2;i++)
{
if(a[i]!=a[flag-i]) return 0;//不符合回文
}
return 1;
}
bool check3(int x) //判断质数
{
if(x==2) return 1;
for(int i=2;i*i<=x;i++)
{
if(x%i==0) return 0;
}
return 1;
}
int main()
{
scanf("%d %d",&l,&r);
if(l==2) printf("2\n");//特判质数2
if(l%2==0) l++;//从奇数开始
r=min(9999999,r);//再大的数都不可能是回文质数
for(int i=l;i<=r;i=i+2)//枚举每一个奇数
{
if(check1(i)==0) continue;
if(check2(i)==0) continue;
if(check3(i)==0) continue;
printf("%d\n",i);//printf比cout快
}
return 0;
}
P1149 [NOIP2008 提高组] 火柴棒等式
题目描述
给你 n 根火柴棍,你可以拼出多少个形如A+B=C 的等式?等式中的 A、B、C 是用火柴棍拼出的整数(若该数非零,则最高位不能是 0)。用火柴棍拼数字0∼9 的拼法如图所示:
注意:
- 加号与等号各自需要两根火柴棍;
- 如果 A≠B,则A+B=C 与B+A=C 视为不同的等式(A,B,C≥0);
- n 根火柴棍必须全部用上。
输入格式
一个整数n(1≤n≤24)。
输出格式
一个整数,能拼成的不同等式的数目。
输入样例1
14
输出样例1
2
输入样例2
18
输出样例2
9
说明/提示
【输入输出样例 1 解释】
2 个等式为 0+1=1和1+0=1。
【输入输出样例 2 解释】
9 个等式为
0+4=4、0+11=11、1+10=11、2+2=4、2+7=9、4+0=4、7+2=9、10+1=11、11+0=11。
题解
#include<iostream>
using namespace std;
int n,s;
int a[2001]={6};//数组的首元素的值为6,其余元素的值为0。
int c[10]={6,2,5,5,4,5,6,3,7,6};
int main()
{
cin>>n;
for(int i=1;i<=2000;i++)
{
int j=i;
while(j>=1)//求每个数所用的火柴棒
{
a[i]+=c[j%10];
j/=10;
}
}
for(int i=0;i<=1000;i++)
{
for(int j=0;j<=1000;j++)
if(a[i]+a[j]+a[i+j]+4==n)s++;//还有加号与等号
}
printf("%d",s);
return 0;
}
P3799 妖梦拼木棒
题目描述
有 n 根木棒,现在从中选 4 根,想要组成一个正三角形,问有几种选法?
答案对1e9+7 取模。
输入格式
第一行一个整数 n。
第二行往下 n 行,每行 1 个整数,第 i 个整数ai 代表第 i 根木棒的长度。
输出格式
一行一个整数代表答案。
输入样例
4
1
1
2
2
输出样例
1
说明/提示
数据规模与约定
- 对于30%的数据,保证n≤5×1e3。
- 对于100%的数据,保证1≤n≤1e5,1≤ai≤5×1e3。
题解
知识点:组合数,暴力
由4根木棒组成一个正三角形,则必有 2根长度相等。
且另外2根长度之和,等于 前2根相等的木棒 的长度。
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int kmax=1e6+10;
const ll kmod=1e9+7;
ll n,ans,maxa,num[kmax],a[kmax];
ll c(ll n,ll k)//组合数
{
//求得从n个数中取出k个数的组合
//最多取两根木棍,采用特判1/2两种
return (k==1ll ? n : n*(n-1)/2ll)%kmod;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
maxa=max(maxa,a[i]);
num[a[i]]++;//统计每种长度木棍根数
}
for(int i=2;i<=maxa;i++)//枚举两根相等的边
{
if(num[i]>=2ll)
{
ll time=c(num[i],2ll)%kmod;//统计组合数
for(int j=1;j<=i/2;j++)//枚举被合成的边(到i / 2即可)
{
if(j!=i-j&&num[j]>=1&&num[i-j]>=1)//用来合成的木棒长度不等
ans+=time*c(num[j],1ll)*c(num[i-j],1ll)%kmod;
if(j==i-j&&num[j]>=2)//用来合成的木棒长度相等
ans+=time*c(num[j],2ll)%kmod;
ans%=kmod;
}
}
}
cout<<ans;
return 0;
}
P2392 kkksc03考前临时抱佛脚
题目描述
这次期末考试,kkksc03 需要考 4 科。因此要开始刷习题集,每科都有一个习题集,分别有s1,s2,s3,s4 道题目,完成每道题目需要一些时间,可能不等(A1,A2,…,As1,B1,B2,…,Bs2,C1,C2,…,Cs3,D1,D2,…,Ds4)。
kkksc03 有一个能力,他的左右两个大脑可以同时计算 2 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。
输入格式
本题包含 5 行数据:第 1 行,为四个正整数s1,s2,s3,s4。
第 2 行,为A1,A2,…,As1 共s1 个数,表示第一科习题集每道题目所消耗的时间。
第 3 行,为B1,B2,…,Bs2 共s2 个数。
第 4 行,为C1,C2,…,Cs3 共s3 个数。
第 5 行,为D1,D2,…,Ds4 共s4 个数,意思均同上。
输出格式
输出一行,为复习完毕最短时间。
输入样例
1 2 1 3
5
4 3
6
2 4 3
输出样例
20
说明/提示
1≤s1,s2,s3,s4≤20。
1≤A1,A2,…,As1,B1,B2,…,Bs2,C1,C2,…,Cs3,D1,D2,…,Ds4≤60。
题解
知识点:动态规划dp、01背包
将时间分配到左右脑,使得两边的时间差最小。
#include<iostream>
using namespace std;
int sum,tot;
int a[5],h[21],dp[2501];//科目、题目、时间
int main()
{
for(int i=1;i<=4;i++)
{
cin>>a[i];
}
for(int i=1;i<=4;i++)
{
sum=0;
for(int j=1;j<=a[i];j++)
{
cin>>h[j];
sum+=h[j];//计算总时间
}
for(int j=1;j<=a[i];j++)
for(int k=sum/2;k>=h[j];k--)//最慢时间为总时长一半
dp[k]=max(dp[k],dp[k-h[j]]+h[j]);//01背包
tot+=sum-dp[sum/2];//累加为另一边脑子
for(int j=1;j<=sum/2;j++) dp[j]=0;//清零
}
cout<<tot;
return 0;
}