1.poj 3071(一道动态规划题)
久疏战阵,这题居然做了一个下午。。
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<math.h>
using namespace std;
#define M 128
int n, team_num, comp_round,num,weight,signal,res_i;
double mat[M][M],win[M][8],temp_win;
int main()
{
for (int i = 0; i < M; ++i)
win[i][0] = 1;
while (scanf_s("%d", &n) && n >= 0)
{
num = 1<<n;
res_i = 0;
//get matrix
for (int i = 0; i < num; ++i)
{
for (int j = 0; j < num; ++j)
{
scanf_s("%lf" ,mat[i]+j);
}
getchar();
}
weight = 1;
for (int j = 1; j <= n; ++j)
{
for (int i = 0; i < num; ++i)
{
signal = (i/weight*weight) ^ (2*weight - 1);
temp_win = 0;
//这里有一种巧妙的方法:判断q和i的二进制前(j-1)位是否相同,这里用异或的方法就行
for (int q = signal; q > signal - weight; --q)
{
temp_win += win[q][j-1] * mat[i][q];
}
win[i][j] = temp_win*win[i][j-1];
}
weight *= 2;//pow(2,j)
}
for (int i = 0; i < num; ++i)
{
if (win[res_i][n] < win[i][n])
{
res_i = i;
}
}
printf("%d\n",res_i+1);
}
return 0;
}
2.
#include"stdafx.h"
#include <iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
#include<math.h>
#include<map>
using namespace std;
int T, N,pai[13],res;
string card;
map<string, int> val;
int main()
{
val.insert(pair<string, int>("A", 1));
val.insert(pair<string, int>("2", 2));
val.insert(pair<string, int>("3", 3));
val.insert(pair<string, int>("4", 4));
val.insert(pair<string, int>("5", 5));
val.insert(pair<string, int>("6", 6));
val.insert(pair<string, int>("7", 7));
val.insert(pair<string, int>("8", 8));
val.insert(pair<string, int>("9", 9));
val.insert(pair<string, int>("10", 10));
val.insert(pair<string, int>("J", 11));
val.insert(pair<string, int>("Q", 12));
val.insert(pair<string, int>("K", 13));
cin >> T;
for (int i = 0; i < T; ++i)
{
cin >> N;
memset(pai, 0, sizeof(pai));
res = 0;
for (int j = 0; j < N; ++j)
{
cin >> card;
pai[val[card]]++;
}
//find consistent array
int c_len = 0;
for (int k = 0; k < 13; ++k)
{
if (k < 13 && pai[k])
c_len++;
else
{
if (c_len > 4)
{
for (int len_i = 5; len_i <= c_len; ++len_i)
{
int temp_multi = 1;
//the last one
for (int len_j = 0; len_j < len_i; ++len_j)
{
temp_multi *= pai[k-1-len_j];
}
res += temp_multi;
//then other former ones
for (int len_l = 1; len_l + len_i <= c_len; ++len_l)
{
res += temp_multi / pai[k - len_l] * pai[k - len_i - 1];
}
}
}
c_len = 0;
}
}
cout << res << endl;
}
return 0;
}
3.poj 3252 动态规划
#include"stdafx.h"
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int input[2], res[2], c[34][34],bin_N[35],
factorial[16] = { 2, 6, 20, 70, 252, 924, 3432, 12870, 48620,184756 ,705432 ,2704156,10400600,40116600, 155117520, 601080390 },
N_LEN_VAL[32] = { 0, 1, 2, 6, 11, 27, 49, 113, 206, 462, 848, 1872, 3458, 7554, 14030, 30414, 56747, 122283, 229045, 491189, 923099, 1971675, 3716111, 7910415, 14946945, 31724161, 60078293, 127187157, 241346585, 509782041, 969094193, 2042836017 };
//1st step: to calculate how many numbers exist in the length of n
long long N_LenNum(int n)
{
if (n <= 1)
return 0;
else if (n == 2)
return 1;
return (1 << (n - 2)) - (n%2?(factorial[n/2-1]/2):0);
}
//2nd step: to transform n from dec to bin
void trans_D2B(int n)
{
int digit = 0;
while (n)
{
bin_N[++digit] = n % 2;
n >>= 1;
}
bin_N[0] = digit;
}
//3rd step: to calculate combination
void cal_combi()
{
c[0][0] = 0;
for (int i = 1; i <= 33; ++i)
{
c[i][0] = c[i][i] = 1;
}
for (int i = 1; i <= 33; ++i)
{
for (int j = i + 1; j <= 33; ++j)
{
c[j][i] = c[j - 1][i - 1] + c[j - 1][i];
}
}
c[0][0] = 1;//why???
}
int main()
{
cal_combi();
/*combinaiton calculation*/
//factorial[0] = 2;
//for (int i = 1; i < 16; ++i)
//{
// factorial[i] = factorial[i-1]/(i+1);
// factorial[i] *= 2 * (i+1);
// factorial[i] /= 1 + i;
// factorial[i] *= 2 * i + 1;
//}
//for (int i = 0; i < 16; ++i)
// cout << factorial[i] << " ,";
/*N_LEN_VALUE calculation*/
//int dat[33];
//memset(dat, 0, sizeof(dat));
//for (int j = 1; j <= 32; ++j)
//{
// dat[j] = dat[j - 1] + N_LenNum(j);
// cout << dat[j]<< ", ";
//}
scanf_s("%d%d",input,input+1);
input[1]++;
res[0] = res[1] = 0;
for (int i = 0; i < 2; ++i)
{
int zero_digit = 0;
trans_D2B(input[i]);
if(bin_N[0] >= 2)
res[i] += N_LEN_VAL[bin_N[0]-2];
for (int j = bin_N[0] - 1; j >= 1; --j)
{
if (bin_N[j])
{
for (int k = (bin_N[0]+1)/2 - zero_digit-1; k <= j-1; ++k)//在余下的j个二进制位中,有k位要为0
res[i] += c[j-1][k];
}
else
zero_digit++;
}
}
printf("%d\n",res[1]-res[0]);
return 0;
}
4.poj 1850 动态规划(类似上一题)
#include"stdafx.h"
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define N 26
char input[N+1],check[N+1];
int c[N+1][N+1];
int str_len = 0,signal = 1,res = 0;//signal == 1 means that the string is legal
void combi()
{
c[0][0] = 1;
for (int i = 1; i <= N; ++i)
c[i][0] = c[i][i] = 1;
for (int i = 1; i <= N; ++i)
for (int j = i + 1; j <= N; ++j)
c[j][i] = c[j - 1][i - 1] + c[j - 1][i];
}
int main()
{
combi();
check[0] = 'a' - 1;
scanf_s("%s",input,N);
//1st step:check its legality
for (int i = 0; input[i]; ++i)
{
str_len++;
check[i + 1] = input[i] + 1;
if (input[i + 1])
{
if (input[i] >= input[i + 1])
{
signal = 0;
break;
}
}
}
if (!signal)
{
printf("%d\n",0);
return 0;
}
//2nd step: calculate the i-length string's number(i < str_len)
for (int i = 1; i < str_len; ++i)
res += c[26][i];
//3rd step: calculate the str_len string's rank
for (int i = 1; i <= str_len; ++i)
{
if (check[i-1] != input[i-1])
{
for (int j = 26 - input[i - 1] + 'a'; j <= 24 + 'a' - (i == 1 ? check[0] : input[i - 2]); ++j)
res += c[j][str_len - i];
}
}
printf("%d\n",res+1);
return 0;
}
4.poj1942
res = C(m+n,n)
如何计算是关键。题目里面说到,m,n,res都是unsigned 32的值,可以考虑采用按定义乘法计算res,或者用递推公式求解的办法。
#include<iostream>
#include<cstdio>
using namespace std;
unsigned long long M,N,res;
//直接用乘法计算结果(我记得有个结论说,C(m,n)总是整数,因此可以用下面的乘法来计算结果)
int main()
{
while(scanf_s("%llu%llu",&M,&N) && (M || N))
{
res = 1;
if(M > N)
{
unsigned long long temp = M;
M = N;
N = temp;
}
for(unsigned long long i = 0;i < M;++i)
{
res *= M+N-i;
res /= i+1;
}
printf("%llu\n",res);
}
return 0;
}
5.poj 1006 中国剩余定理
#include"stdafx.h"
#include<stdio.h>
#include<iostream>
#include<string.h>
#define M 21252
using namespace std;
int main()
{
int p, e, i, d,res,case_n = 0;
while (scanf_s("%d%d%d%d",&p,&e,&i,&d) && (p + e + i + d != -4))
{
case_n++;
res = (5544 * p+14421*e+1288*i-d)%M;
if (res)
res = (res + M) % M;
else
res = M;
printf("Case %d: the next triple peak occurs in %d days.\n",case_n,res);
}
return 0;
}
6.poj 2635
参考博客:https://www.cnblogs.com/kuangbin/archive/2012/04/01/2429463.html
采用了素数打表,和改成千进制运算求模的思想
#include"stdafx.h"
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<vector>
#define M 1000
#define N 10000 //here we transfer from 1000-scale to 10000-scale
#define Nn 4
#define MM M*M
using namespace std;
bool primes[MM+1],signal;//(prime num is marked as 0)
int rec_prime[80*M],Kt[40];
char str[110];
int L, p,temp,prime_num = 0;
bool mod_N(int len, int p)
{
long long re = 0;//notice that here 10000^2 + any_num is very likely to exceed 2^32-1
for (int i = len - 1; i >= 0; --i)
re = (re * N + Kt[i]) % p;
return !!re;
}
void output_prime()
{
//set the array's initial value as 0
memset(primes,0,sizeof(primes));
for (int i = 4; i <= MM; i += 2)
primes[i] = 1;
for (int i = 3; i <= M; i += 2)
{
if (!primes[i])
{
temp = 2 * i;
for (int j = i*i; j <= MM; j += temp)
{
primes[j] = 1;
}
}
}
for (int i = 2; i < MM; ++i)
if (!primes[i])
rec_prime[prime_num++] = i;
rec_prime[prime_num++] = 1000003;
}
int main()
{
//1st step: to create a table(All even composite numbers are not marked!!)
output_prime();
//2nd step: to check if K/table[i] is an integer, we use mod
while (scanf_s("%s%d", str, 110,&L), L)
{
int str_len = strlen(str);
memset(Kt, 0, sizeof(Kt));
signal = true;
for (int i = 0; i < str_len; ++i)
{
int th_i = (str_len + Nn-1 - i) / Nn - 1;
Kt[th_i] = Kt[th_i] * 10 + str[i] - '0';
}
str_len = (str_len + Nn-1) / Nn;
for (int pi = 0; rec_prime[pi] < L; ++pi)
{
if (!mod_N(str_len, rec_prime[pi]))
{
signal = false;
printf("BAD %d\n", rec_prime[pi]);
break;
}
}
if(signal)
printf("GOOD\n");
}
return 0;
}
7.poj 3292
我一开始采用了类似素数筛法的方法计算,发现在自己电脑上都不能运行出结果,这说明我的算法计算量太大,不适用于这题。
接着我参考了博客,里面的思路比较暴力,直接开一个数组去记录它的结果状态,然后再遍历一遍即可。为什么原先用素数筛法的方法不行了呢?我输出了H-prime的个数(1,000,000以内),有约270,000个,也就是27%。而质数在一百万里仅有约1/ln(x),就是7%左右,由于数目相差悬殊,所以计算量相差很大,因此用暴力方法反而更快一些。
#include"stdafx.h"
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 1000001
int h, H[N],multi,H_Number[250001],
prime_count = 0;
void H_Num()
{
memset(H, 0, sizeof(H));
for (int i = 5; i <= N; i += 4)
{
for (int j = 5; j <= N; j += 4)
{
multi = i * j;
if (multi > N)
break;
if (H[i] == 0 && H[j] == 0)
H[multi] = 1;
else
H[multi] = -1;
}
}
multi = 0;
for (int i = 1; i <= 250000; i++)
{
if (H[(i<<2)+1] == 1)
{
multi++;
}
H_Number[i] = multi;
}
}
int main()
{
H_Num();
while (scanf_s("%d",&h),h)
printf("%d %d\n",h,H_Number[h/4]);
return 0;
}
8.poj 2115
一道经典的求解模线性方程题目。算法参考《算法导论》p555。参考博客:https://blog.csdn.net/lyy289065406/article/details/6648546
这里有一点要讲,就是1LL<<k与1<<k是有区别的(对于long long 类型来说)!
#include"stdafx.h"
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
long long A,B,C,k,a,b,n,d,ex,ey;
long long ExtendedEuclid(long long a, long long b,long long &x,long long &y)
{
if (!b)
{
ex = 1;
ey = 0;
return a;
}
else
{
long long d = ExtendedEuclid(b,a%b,ex,ey);
long long temp_ex = ex;
ex = ey;
ey = temp_ex - a / b * ey;
return d;
}
}
int main()
{
while (scanf_s("%lld%lld%lld%lld", &A, &B, &C, &k), k)
{
a = C;
b = B - A;
n = 1 << k;
d = ExtendedEuclid(a,n,ex,ey);
if (b % d)
{
printf("FOREVER\n");
continue;
}
else
{
ex = ex * b / d % n;
ex = (ex%(n/d)+n/d) % (n/d);
printf("%lld\n",ex);
}
}
return 0;
}
9.poj 1002
(1)巧妙地存储带字符的字符串:用int数组存储(参考博客:https://blog.csdn.net/thebestdavid/article/details/10986813)。
(2)想输出整数的部分时,用setw()或者%04d,4表示保留4位,0表示不足补零。
#include"stdafx.h"
#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
char input_str[100];
int phone_num[100010];
void print_phone(int num,int c)
{
for (int i = 0; i < 7; ++i)
{
}
}
int main()
{
int total_num,phone_len,phone_value,dup_num = 0,signal = 0;
scanf_s("%d",&total_num);
for (int gi = 0; gi < total_num; ++gi)
{
scanf_s("%s",input_str,100);
phone_len = strlen(input_str);
phone_value = 0;
for (int si = 0; si < phone_len; ++si)
{
//transfer string to int
if (input_str[si] == '-')
continue;
//get number
else if (input_str[si] >= '0' && input_str[si] <= '9')
{
phone_value *= 10;
phone_value += input_str[si] - '0';
}
else
{
phone_value *= 10;
switch (input_str[si])
{
case 'A':
case 'B':
case 'C': phone_value += 2; break;
case 'D':
case 'E':
case 'F': phone_value += 3; break;
case 'G':
case 'H':
case 'I':phone_value += 4; break;
case 'J':
case 'K':
case 'L':phone_value += 5; break;
case 'M':
case 'N':
case 'O':phone_value += 6; break;
case 'P':
case 'R':
case 'S':phone_value += 7; break;
case 'T':
case 'U':
case 'V':phone_value += 8; break;
case 'W':
case 'X':
case 'Y':phone_value += 9; break;
}
}
}
phone_num[gi] = phone_value;
}
sort(phone_num,phone_num+total_num);
for (int pi = 0,counter = 0; pi < total_num; ++pi)
{
if (!pi || phone_num[pi - 1] == phone_num[pi])
{
counter++;
if (pi + 1 == total_num)
{
printf("%03d-%04d %d\n", phone_num[pi] / 10000, phone_num[pi] % 10000, counter);
signal = 1;
}
}
else if(counter > 1)
{
printf("%03d-%04d %d\n", phone_num[pi-1]/10000, phone_num[pi - 1]%10000,counter);
signal = 1;
counter = 1;
}
}
if (!signal)
printf("No duplicates.\n");
return 0;
}
10. poj 2063 一道完全背包 代码思路是参照https://blog.csdn.net/hmc0411/article/details/78398872这篇博客的。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int bond[11], v[11], dp[47002];
int add(int m, int n){
m /= 1000;
for(int i = 1; i <= n; ++i){
for(int j = bond[i]; j <= m; ++j){
dp[j] = max(dp[j], dp[j - bond[i]] + v[i]);
}
}
return dp[m];
}
int main(){
int T;
scanf("%d", &T);
while(T--){
int n, m, d;
scanf("%d %d %d", &m, &d, &n);
for(int i = 1; i <= n; ++i){
scanf("%d %d", &bond[i], &v[i]);
bond[i] /= 1000;
}
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= d; ++i){
m += add(m, n);
}
printf("%d\n", m);
}
}
/*
题意:一家银行,10种不同的投资方案,每种有一个投资金额和每年的回报额,最多40年,每年得到的
回报额可以参加下一年投资。问n年后最多可以得到多少钱?
思路:
对于每一年来说,用完全背包求最大收益是很容易的。那么对于n年,我们只需要把每年的收益加上去再求
新的一次背包就好了。最多40年,每年收益比最大0.1,求一下背包的上限。然后暴力跑背包就好了。
*/
11.poj 1252 完全背包(两次) 参考:https://www.cnblogs.com/xinsheng/p/3457126.html
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<iostream>
#include<map>
#include<vector>
using namespace std;
int dp[2010],cash[6];
int main()
{
int N,maxRes;
double averRes;
scanf_s("%d",&N);
while(N--)
{
averRes = maxRes = 0;
//get input
for (int j = 0; j < 6; ++j)
scanf_s("%d", &cash[j]);
memset(dp,2100,sizeof(dp));
dp[0] = 0;
//dp for addition
for (int i = 0; i < 6; ++i)
{
for (int j = cash[i]; j <= 2000; ++j)
{
dp[j] = min(dp[j],dp[j-cash[i]]+1);
}
}
//dp for subtraction
for (int i = 0; i < 6; ++i)
{
for (int j = 2000 - cash[i]; j >= 1; --j)
{
dp[j] = min(dp[j],dp[j+cash[i]]+1);
}
}
for (int i = 1; i <= 100; ++i)
{
averRes += dp[i];
maxRes = max(maxRes, dp[i]);
}
printf("%0.2f %d\n",averRes/100.0,maxRes);
}
}
12. poj 1948 背包问题 参考https://blog.csdn.net/xiefubao/article/details/23224659
#include"stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include<cstdio>
#include<math.h>
#include<algorithm>
using namespace std;
#define LEN 40
#define P 800
bool OK(int i, int j, int k)
{
return ((i + j) > k) && ((i + k) > j) && ((j+k)>i);
}
double getarea(int i, int j, int k)
{
double p = (i + j + k) / 2.0;
return sqrt(p*(p-i)*(p-j)*(p-k));
}
int main()
{
int N, periM = 0,sides[LEN+1];
double res = 0;
bool dp[P + 1][P + 1];
//get input
scanf_s("%d",&N);
for (int i = 0; i < N; ++i)
{
scanf_s("%d", &sides[i]);
periM += sides[i];
}
//check whether triangle exists
dp[0][0] = 1;
for (int i = 0; i < N; ++i)
{
for (int k = periM/2; k >= 0; --k)
{
for (int j = k; j >= 0; --j)
{
if (k - sides[i] >= 0 && dp[k - sides[i]][j])//保证k是边长集合中部分元素之和
dp[k][j] = 1;
if (j - sides[i] >= 0 && dp[k][j - sides[i]])//dp[k][j]可以从dp[k-sides[i]][j]获取,也可以从dp[k][j-sides[i]]获取
dp[k][j] = 1;
}
}
}
for (int i = 0; i <= periM/2; ++i)
{
for (int j = 0; j <= i; ++j)
{
if (dp[i][j] && OK(i, j, periM - i - j))
res = max(res, getarea(i, j, periM - i - j));
}
}
if (res == 0)
printf("-1\n");
else
printf("%d\n",(int)(res*1000)/10);
return 0;
}
13. poj 1976 01背包问题
#include"stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include<stdlib.h>
#include<cstdio>
#include<math.h>
#include<algorithm>
#define NUM 50001
using namespace std;
int capa[NUM], sumC[NUM],dp[4][NUM];
int main()
{
int rounds, lenTrain,pullNum;
scanf_s("%d",&rounds);
while (rounds--)
{
//get input
scanf_s("%d",&lenTrain);
capa[0] = 0;
for (int i = 1; i <= lenTrain; ++i)
scanf_s("%d",&capa[i]);
scanf_s("%d",&pullNum);
sumC[0] = capa[0];
for (int i = 1; i <= pullNum; ++i)
sumC[i] = sumC[i-1] + capa[i];
for (int i = pullNum+1; i <= lenTrain; ++i)
sumC[i] = sumC[i-1] + capa[i] - capa[i - pullNum];
//dp recursion
memset(dp,0,sizeof(dp));
for (int i = 1; i <= 3; ++i)
for (int j = pullNum; j <= lenTrain; ++j)
dp[i][j] = max(dp[i][j-1],dp[i-1][j-pullNum]+sumC[j]);
printf("%d\n",dp[3][lenTrain]);
}
}
14. poj 3904 莫比乌斯反演 参考https://blog.csdn.net/qq_42671946/article/details/89161719
#include"stdafx.h"
#include <iostream>
#include <vector>
#include <string.h>
#include<stdlib.h>
#include<cstdio>
#include<string.h>
#include<math.h>
#include<algorithm>
#define N 10001
using namespace std;
int mobius[N],input[N],F[N];
bool sig[N];
//计算莫比乌斯函数
void mobiusFunc()
{
int i, j;
for (i = 1; i < N; ++i)
{
mobius[i] = 1;
sig[i] = false;
}
for (i = 2; i < N; ++i)
{
if (sig[i])//如果已经处理过,则跳过
continue;
for (j = i; j < N; j += i)
{
sig[j] = true;
if ((j / i) % i == 0)
{
mobius[j] = 0;//如果因数包含某素数的多次方,则置零
continue;
}
mobius[j] = -mobius[j];//遍历到数字j,表示素数i是j的因数,所以要变号
}
}
}
//计算组合数C(4,m)
long long combinCalclu(long long num)
{
return num * (num - 1)*(num - 2)*(num - 3) / 24;
}
int main()
{
mobiusFunc();
int n;
//get input
while (scanf_s("%d",&n) == 1)
{
int maxNum = 0;
for (int i = 0; i < n; ++i)
{
scanf_s("%d", &input[i]);
maxNum = max(maxNum,input[i]);
}
//计算gcd为1的倍数的四元组个数
memset(F,0,sizeof(F));
for (int i = 0; i < n; ++i)
{
for (int j = 1; j*j <= input[i]; ++j)
{
if (input[i] % j == 0)
{
F[j]++;
if (j*j != input[i])
F[input[i] / j]++;
}
}
}
//根据莫比乌斯反演公式求得
long long res = 0;
for (int i = 1; i <= maxNum; ++i)
{
if (F[i] >= 4)
res += mobius[i] * combinCalclu(F[i]);
}
printf("%lld\n",res);
}
}