P2241 统计方形(数据加强版)
这道题目需要的数学结论如下:
对于一个 n × m 的棋盘,我们要求其中的矩形个数(正方形+长方形)有公式如下:
(1 + 2 + 3 + ... + n) × (1 + 2 + 3 + ... + m) = (n + 1) × n/2 × (m + 1) × m/2
而对于一个n×n的棋盘,我们要求其中的正方形个数有如下公式:
1×1 + 2×2 + 3×3 + ... + n×n
那么对于n×m的棋盘,我们要求其中的正方形个数有如下公式:
∑ ( n − i + 1 )( m − i + 1) 其中i从 1 到 min ( n , m )
#include<iostream>
using namespace std;
#define ll long long
int main() {
ll n, m,sum,sum1=0,sum2,p=0;
cin >> n >> m;
sum = (n + 1) * n * (m + 1) * m / 4;
p = n < m ? n : m;
for (ll i = 1; i <= p; i++) {
sum2 = (n - i + 1) * (m - i + 1);
sum1 += sum2;
}
cout << sum1 << " " << sum - sum1;
}
P2089 烤鸡
这道题目 10 层 for 循环就可以很暴力的 AC
#include<iostream>
using namespace std;
#define ll long long
int main() {
ll n, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, cnt = 0, flag = 0;
cin >> n;
for (i1 = 1; i1 <= 3; i1++) {
for (i2 = 1; i2 <= 3; i2++) {
for (i3 = 1; i3 <= 3; i3++) {
for ( i4 = 1; i4 <= 3; i4++) {
for (i5 = 1; i5 <= 3; i5++) {
for (i6 = 1; i6 <= 3; i6++) {
for (i7 = 1; i7 <= 3; i7++) {
for ( i8 = 1; i8 <= 3; i8++) {
for ( i9 = 1; i9 <= 3; i9++) {
for (i10 = 1; i10 <= 3; i10++) {
if (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10==n) {
flag = 1;
cnt++;
}
}
}
}
}
}
}
}
}
}
}
if (flag == 0)
cout << flag;
if (flag == 1)
cout << cnt << endl;
for (i1 = 1; i1 <= 3; i1++) {
for (i2 = 1; i2 <= 3; i2++) {
for (i3 = 1; i3 <= 3; i3++) {
for (i4 = 1; i4 <= 3; i4++) {
for (i5 = 1; i5 <= 3; i5++) {
for (i6 = 1; i6 <= 3; i6++) {
for (i7 = 1; i7 <= 3; i7++) {
for (i8 = 1; i8 <= 3; i8++) {
for (i9 = 1; i9 <= 3; i9++) {
for (i10 = 1; i10 <= 3; i10++) {
if (i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 == n) {
cout << i1 << " " << i2 << " " << i3 << " " << i4 << " " << i5 << " " << i6 << " " << i7 << " " << i8 << " " << i9 << " " << i10 << endl;
}
}
}
}
}
}
}
}
}
}
}
}
P1618 三连击(升级版)
这道题目 3 层 for 循环就可以很暴力的 AC
#include<iostream>
using namespace std;
#define ll long long
//arr数组用来记录哪些数字被使用
ll arr[10] = {0,1,2,3,4,5,6,7,8,9 };
//求三位数的函数
ll num(ll i, ll j, ll k) {
return 100 * i + 10 * j + k;
}
int main() {
ll a, b, c, i, j, k, num1, num2, num3, i1, j1, k1, i2, j2, k2,cnt=0,s=0;
cin >> a >> b >> c;
if (a != 0) {
//三层for循环枚举所有的三位数
for (i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
for (k = 1; k < 10; k++) {
//该三位数的三个数字肯定不能相同
if (i != j && i != k && j != k) {
//求出三位数
num1 = num(i, j, k);
//记录被使用的数字,赋值为0
arr[i] = 0;
arr[j] = 0;
arr[k] = 0;
//利用比例先计算出另外两个三位数
num2 = num1 * b / a;
num3 = num2 * c / b;
//判断后,记录被使用的数字
if (num1 < 987 && num2 < 987 && num3 < 987) {
i1 = num2 / 100;
k1 = num2 % 10;
j1 = num2 % 100 / 10;
i2 = num3 / 100;
k2 = num3 % 10;
j2 = num3 % 100 / 10;
arr[i1] = 0;
arr[j1] = 0;
arr[k1] = 0;
arr[i2] = 0;
arr[j2] = 0;
arr[k2] = 0;
//只有所有数字均被使用才进行输出,并且随之计数
if (arr[0] == 0 && arr[1] == 0 && arr[2] == 0 && arr[3] == 0 && arr[4] == 0 && arr[5] == 0 && arr[6] == 0 && arr[7] == 0 && arr[8] == 0 && arr[9] == 0) {
cout << num1 << " " << num2 << " " << num3 << endl;
cnt++;
}
//数组要开始准备重新记录
for (s = 0; s < 10; s++) {
arr[s] = s;
}
}
}
}
}
}
}
//不存在的特殊情况
if (cnt == 0 || a == 0) {
cout << "No!!!" << endl;
}
return 0;
}
P1036 [NOIP2002 普及组] 选数
#include<iostream>
using namespace std;
int n, k, a[25], ans;
//判断素数函数
int isprime(int x) {
for (int i = 2; i * i < x; i++)
if (x % i == 0)
return 0;
return 1;
}
//递归函数(开始位置,选择个数,选择之和)
void dfs(int start, int cnt, int sum) {
//选择完成
if (cnt == 0 ) {
//所选择的和是素数则计算器加一
if (isprime(sum) == 1)
ans++;
return; //返回
}
//个数不足
if (n - start + 1 < cnt)
return; //返回
for (int i = start; i <= n; i++)
//递归(位置加一,个数减一,加入所选数字)
dfs(i + 1, cnt - 1, sum + a[i]);
}
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
dfs(1, k, 0);
cout << ans;
return 0;
}
P1157 组合的输出
#include<iostream>
using namespace std;
int n, r;
//num数组为数字,flag数组为标记,1为选择,0为没有被选择
int num[25], flag[25];
//递归函数(开始位置,选择个数)
void dfs(int start, int cnt) {
//选择完毕,直接输出
if (cnt == 0) {
for (int i = 1; i <= n; i++)
if (flag[i] == 1)
//注意题目要求的输出格式
printf("%3d", num[i]);
cout << endl;
return ;
}
//个数不足直接结束
if (n - start + 1 < cnt)
return;
//从开始位置遍历
for (int i = start; i <= n; i++) {
//选择后进行标记1
flag[i] = 1;
//递归
dfs(i + 1, cnt - 1);
//递归回来要重新标记为0
flag[i] = 0;
}
}
int main() {
cin >> n >> r;
for (int i = 1; i <= n; i++)
num[i] = i;
dfs(1, r);
return 0;
}
P1706 全排列问题
#include<iostream>
using namespace std;
//num数组存数字,flag数组来记录,1为已选择,0为未选择
int n, num[10], flag[10];
//递归函数(全排列总数)
void dfs(int cnt) {
//所有数均选好
if (cnt == 0) {
//注意倒着输出数组num
for (int i = n; i > 0; i--)
printf("%5d", num[i]);
cout << endl;
return; //返回
}
//遍历
for (int i = 1; i <= n; i++) {
//如果没有选择
if (flag[i] == 0) {
//把该数字存到(倒着存)数组num中
num[cnt] = i;
flag[i] = 1; //标记选择
dfs(cnt - 1); //递归
flag[i] = 0; //回溯后返回原标记0
}
}
}
int main() {
cin >> n;
dfs(n);
return 0;
}
其中 选数 组合输出 全排列 这三道题要好好区分,熟练掌握
P1088 [NOIP2004 普及组] 火星人
在这里我们可以直接使用 next_permutation(起始位置 , 结束位置) 函数,
它是C++STL提供的一个函数,用于求一个序列的下一个字典序排列,
使用时要加头文件:#include<algorithm>
#include<iostream>
#include<algorithm>
using namespace std;
int n, m, a[10005];
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++)
cin >> a[i];
for (int i = 1; i <= m; i++)
next_permutation(a, a + n);
for (int i = 0; i <= n - 2; i++)
cout << a[i] << " ";
cout << a[n - 1];
return 0;
}
P3392 涂国旗
#include<iostream>
using namespace std;
int n, m;
char ch[55][55];
//定义一个稍微大一点的 ans 记录答案
long long ans = 10000;
//计数函数
long long count(int a, int b, int c) {
long long cnt = 0;
//白色区域
for (int i = 1; i <= a; i++)
for (int j = 1; j <= m; j++)
if (ch[i][j] != 'W')
cnt++;
//蓝色区域
for (int i = a + 1; i <= b; i++)
for (int j = 1; j <= m; j++)
if (ch[i][j] != 'B')
cnt++;
//红色区域
for (int i = b + 1; i <= c; i++)
for (int j = 1; j <= m; j++)
if (ch[i][j] != 'R')
cnt++;
return cnt;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> ch[i][j];
int start = 1, mid = 2, end = n;
//双重 while 循环划分所有可能存在的区域
while (start <= n - 2) {
while (mid <= n - 1) {
//临时数据 temp 存储该情况的数字
long long temp = count(start, mid, end);
//每次计算完进行比较,更新答案
ans = temp < ans ? temp : ans;
//更新 mid 下标
mid++;
}
//更新 start mid 下标
start++;
mid = start + 1;
}
cout << ans;
return 0;
}
P3654 First Step (ファーストステップ)
这题注意一下K==1的时候的特殊判断即可
#include<iostream>
using namespace std;
const int N=105;
int R,C,K,ans;
char ch[N][N];
int main(){
cin>>R>>C>>K;
for(int i=1;i<=R;i++) for(int j=1;j<=C;j++) cin>>ch[i][j];
for(int i=1;i<=R;i++){
for(int j=1;j<=C;j++){
if(ch[i][j]=='.'){
if(j+K-1<=C){
bool flag=1;
for(int x=j;x<=j+K-1;x++) if(ch[i][x]!='.') {flag=0;break;}
if(flag) ans++;
}
if(i+K-1<=R){
bool flag=1;
for(int x=i;x<=i+K-1;x++) if(ch[x][j]!='.') {flag=0;break;}
if(flag) ans++;
}
}
}
}
if(K==1) cout<<ans/2<<endl;
else cout<<ans<<endl;
return 0;
}
P1217 [USACO1.5] 回文质数 Prime Palindromes
暴力超时:
#include<iostream>
#include<cmath>
using namespace std;
int a,b,ans;
//质数
bool check1(int x){
if(x<2) return false;
for(int i=2;i<=x/i;i++) if(x%i==0) return false;
return true;
}
//回文
bool check2(int x){
int num[20],flag=0;
while(x>0){
num[flag++]=x%10;
x/=10;
}
for(int i=0;i<flag/2;i++) if(num[i]!=num[flag-i-1]) return false;
return true;
}
int main(){
cin>>a>>b;
if(b>10000000) b=10000000;
for(int i=a;i<=b;i++) if(check1(i)&&check2(i)) cout<<i<<endl;
return 0;
}
优化 AC:
#include<iostream>
using namespace std;
const int N=1e8+5;
int a,b,ans;
//线性筛法
int primes[N],cnt;
bool flag[N];
void get_primes(){
for(int i=2;i<=b;i++){
if(!flag[i]) primes[cnt++]=i;
for(int j=0;primes[j]<=b/i;j++){
flag[primes[j]*i]=1;
if(i%primes[j]==0) break;
}
}
}
//回文
bool check(int x){
int t=x,res=0;
while(t!=0){
res=res*10+t%10;
t/=10;
}
return res==x;
}
int main(){
cin>>a>>b;
b=min(b,(int)1e8);
get_primes();
for(int i=0;i<=cnt;i++) if(primes[i]>=a&&check(primes[i])) cout<<primes[i]<<endl;
return 0;
}
试除法判定质数 O(sqrt(n))
bool check_prime(int x){
if(x<2) return 0;
for(int i=2;i<=x/i;i++) if(x%i==0) return 0;
return 1;
}
埃拉托斯特尼筛法 O(nloglogn)
int n,cnt,prime[N];
bool flag[N];
void get_prime(){
for(int i=2;i<=n;i++){
if(!flag[i]){
prime[cnt++]=i;
for(int j=i;j<=n;j+=i) flag[j]=1;
}
}
}
线性筛法 O(n)
int n,cnt,prime[N];
bool flag[N];
void get_prime(){
for(int i=2;i<=n;i++){
if(!flag[i]){
prime[cnt++]=i;
for(int j=0;prime[j]<=n/i;j++){
flag[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
}
P1149 [NOIP2008 提高组] 火柴棒等式
#include<iostream>
using namespace std;
int n,ans,a[10005],match[10]={6,2,5,5,4,5,6,3,7,6};
int fun(int z){
if(z<=9) return match[z];
else{
int temp=0;
while(z>0){
temp+=match[z%10];
z/=10;
}
return temp;
}
}
void dfs(int x,int sum){
if(sum>n) return ;
if(x>3){
if(a[1]+a[2]==a[3]&&sum==n){
ans++;
}
return ;
}
for(int i=0;i<=1000;i++){
a[x]=i;
dfs(x+1,sum+fun(i));
a[x]=0;
}
}
int main(){
cin>>n;n-=4;
dfs(1,0);
cout<<ans<<endl;
return 0;
}
P2392 kkksc03考前临时抱佛脚
暴力搜索 AC:
#include<iostream>
using namespace std;
const int N=25;
int n[5],a[5][25],l,r,ans,res=0x3f3f3f3f;
void dfs(int id,int x){
if(id>n[x]){
res=min(res,max(l,r));
return ;
}
//左脑
l+=a[x][id];
dfs(id+1,x);
l-=a[x][id];
//右脑
r+=a[x][id];
dfs(id+1,x);
r-=a[x][id];
}
int main(){
for(int i=1;i<=4;i++) cin>>n[i];
for(int i=1;i<=4;i++){
for(int j=1;j<=n[i];j++){
cin>>a[i][j];
}
dfs(1,i);
ans+=res;
l=0,r=0,res=0x3f3f3f3f;
}
cout<<ans<<endl;
return 0;
}
P2036 [COCI2008-2009 #2] PERKET
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+5;
int n,a[N],b[N],c[N],i=1,j=1,k=1;
long long ans;
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++) cin>>c[i];
sort(a+1,a+n+1);
sort(b+1,b+n+1);
sort(c+1,c+n+1);
long long ta=1,tc=1,cnta=0,cntc=0;
for(j=1;j<=n;j++){
for(i=ta;i<=n;i++){
if(b[j]>a[i]){
cnta++;
}
else{
break;
}
}
for(k=tc;k<=n;k++){
if(c[k]>b[j]){
break;
}
else{
cntc++;
}
}
ans+=cnta*(n-cntc);
ta=cnta+1;
tc=cntc+1;
}
cout<<ans<<endl;
return 0;
}
P3799 小Y拼木棒
枚举木棒的长度,并且分相等和不相等分别计算即可
注意开浪浪以及枚举的顺序
#include<iostream>
#define int long long
using namespace std;
const int N=5e3+5,mod=1e9+7;
int n,ans,flag[N];
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
flag[x]++;
}
for(int i=1;i<=5000;i++){
for(int j=i;j<=5000&&i+j<=5000;j++){
if(i==j){
int x=flag[i],y=flag[i+j];
if(x>=2&&y>=2) ans=(ans+y*(y-1)/2*x*(x-1)/2)%mod;
}
else{
int x=flag[i],y=flag[j],z=flag[i+j];
if(x>=1&&y>=1&&z>=2) ans=(ans+z*(z-1)/2*x*y)%mod;
}
}
}
cout<<ans<<endl;
return 0;
}