POJ杂题题解
POJ1147
根据最后一列,可以确定答案中0/1的个数,同样第一列也确定了,因为每次操作之后得到的矩阵都是排过序的,不妨考虑一下把最后一列移到第一列,这样可以得到最后一列与第一列排序的对应关系,然后根据这个对应关系就可以知道每一行经过排序会发生什么变化,这样不断递推就可以求出整个矩阵了。由于只需要第一行,输出即可。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define P system("pause");
#define B printf("Break\n");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000
int read()
{
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
}
return f * x;
}
#define N 3010
int f[N],nxt[N],ans[N];
int main()
{
int n = read(),cnt = 0;
for(int i = 1;i <= n;++i) f[i] = read();
int tot = 0;
for(int i = 1;i <= n;++i)
if(!f[i]) nxt[++tot] = i;
for(int i = 1;i <= n;++i)
if(f[i]) nxt[++tot] = i;
for(int i = 1,pos = nxt[1];i <= n;++i)
{
printf("%d ",f[pos]);
pos = nxt[pos];
}
putchar('\n');
}
POJ1163
数字三角形,dp入门题。
\(f_{x,y} = \max (f_{x+1,y},f_{x+1,y+1}) + a_{x,y}\)
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define P system("pause");
#define B printf("Break\n");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000
int read()
{
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
}
return f * x;
}
#define N 150
int f[N][N],a[N][N],n;
int dfs(int x,int y)
{
if(f[x][y]) return f[x][y];
if(x == n) return f[n][y] = a[n][y];
else return f[x][y] = max(dfs(x + 1,y),dfs(x + 1,y + 1)) + a[x][y];
}
int main()
{
n = read();
for(int i = 1;i <= n;++i)
for(int j = 1;j <= i;++j)
a[i][j] = read();
printf("%d\n",dfs(1,1));
}
POJ1922
理性分析一下,发现这个人一定会跟着骑得最快的人一块骑,因此只需统计出最先到达终点的人的时间即可。注意在0时刻之前出发的,要么一定会被这个人超过,要么永远追不上,所以不予考虑。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define P system("pause");
#define B printf("Break\n");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000
int read()
{
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
}
return f * x;
}
int main()
{
int n;
while(~scanf("%d",&n) && n)
{
double ans = inf;
for(int i = 1;i <= n;++i)
{
double v,t,dt = inf;
scanf("%lf%lf",&v,&t);
if(t >= 0) dt = ceil(t + 4.5 / (v / 3600.0));
ans = min(ans,dt);
}
printf("%d\n",(int)ans);
}
}
POJ2211
题目大意:给定 \(n\), \(k\), 求给定排列在所有 \(A_n^k\) 种排列中的排名的字典序。
这个题一看就跟组合数有关系,假设得到的排列是 \(x_1,x_2,...,x_k\) ,考虑所有比这个排列小的,按位考虑,显然所有第一个元素比 \(x_1\) 小的都符合,这些排列一共有 \((x_1-1)A_{n-1}^{k-1}\)个。然后继续往后考虑,到第 \(i\) 个元素,符合条件的是 \((x_i-1)A_{n-i}^{k-i}\) ,但是这里的 \(x_i\) 有一点变化,如果前面已经考虑过比这个 \(x_i\) 小的元素了,那么就需要去重,具体方法见代码。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define P system("pause");
#define B printf("Break\n");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000
ll read()
{
ll x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
}
return f * x;
}
#define N 20
ll fac[N],x[N];
ll a(ll n,ll m)
{
if(n < m) return 0;
return fac[n] / fac[n - m];
}
int main()
{
ll T = read();fac[0] = 1;
for(ll i = 1;i <= 12;++i) fac[i] = fac[i - 1] * i;//预处理阶乘
for(ll j = 1;j <= T;++j)
{
ll n = read(),k = read(),ans = 0;
for(ll i = 1;i <= k;++i) x[i] = read();
for(ll i = 1;i <= k;++i)
{
ans += (x[i] - 1) * a(n - i,k - i);//按位计算
for(int l = i + 1;l <= k;++l)
if(x[l] > x[i]) x[l]--;//这里去重
}
printf("Variace cislo %lld ma poradove cislo %lld.\n",j,ans + 1);//诡异的输出格式
}
}
POJ2215
题目大意:给定一个矩形,内部每个点有权值,多次询问一个子矩形内部权值和。
就是个水题啊,二维前缀和一下就搞定了。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define P system("pause");
#define B printf("Break\n");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000
int read()
{
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
}
return f * x;
}
#define N 1010
int a[N][N],sum[N][N];
int main()
{
int T = read();
while(T--)
{
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
int r = read(),s = read();
for(int i = 1;i <= r;++i)
{
for(int j = 1;j <= s;++j)
{
a[i][j] = read();
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
}
}
int q = read();
while(q--)
{
int r1 = read(),s1 = read(),r2 = read(),s2 = read();
int ans = sum[r2][s2] - sum[r2][s1 - 1] - sum[r1 - 1][s2] + sum[r1 - 1][s1 - 1];
printf("Absolutni hodnota pohodlnosti je %d bodu.\n",ans);
}
puts("");
}
}
POJ2229
题目大意:求一个数 \(n\) 按照2的幂次拆分的方案数。
看到方案数,又看到数据范围 \(n \leq 10^6\) ,那就是dp了呗。
定义 \(dp_i\) 为拆分数 \(i\) 的方案数,它可以从 \(i-1,i-2,...,i-2^k\) 转移过来。故方程显然:
再仔细一看,这不就是完全背包的形式吗,有 \(\log_2n\) 件物品,求装入体积为 \(n\) 的背包的方案总数。
\(O(n\log n)\) 复杂度。
还有一种打表找规律做到 \(O(n)\) 的方法,当 \(i\) 为奇数时,它只能通过 \(i-1+2^0\) 得到,比如:\(5\) 只能通过 \(4+2^0\) 得到,当 \(i\) 为偶数时,它既可以通过 \(i-1+2^0\) ,又可以通过 \(\dfrac{i}{2}*2\) 得到,比如:\(6\) 可以通过 \(5+2^0\) 得到,也可以通过 \(3*2\) 得到。
代码是完全背包做法。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define P system("pause");
#define B printf("Break\n");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000
int read()
{
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
}
return f * x;
}
#define N 1000100
#define mod 1000000000
int dp[N],a[30];
int main()
{
int n = read();
int tot = 1,cnt = 0;
while(tot <= n) a[++cnt] = tot,tot <<= 1;
dp[0] = 1;
for(int i = 1;i <= cnt;++i)
{
for(int j = a[i];j <= n;++j)
{
dp[j] = (dp[j] + dp[j - a[i]]) % mod;
}
}
printf("%d\n",dp[n]);
}
POJ2232
什么叫“随机”啊,那就是可以随便操作的意思。如果三种手势都有,我们完全可以直接操作一下让每个人都获胜,因为保证了不存在平局嘛。而如果只有两种手势,那就只能是赢的那种手势的人才能获胜。一种手势比较显然,都可以获胜。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define P system("pause");
#define B printf("Break\n");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000
int read()
{
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
}
return f * x;
}
int main()
{
int n;
while(scanf("%d \n",&n) != EOF)
{
int sums = 0,sumc = 0,sumf = 0;
string s;
getline(cin,s);
for(int i = 0;i < s.size();++i)
{
if(s[i] == 'C') sumc++;
if(s[i] == 'S') sums++;
if(s[i] == 'F') sumf++;
}
if((sumf != 0 && sums != 0 && sumc != 0) || (sumf == n || sums == n || sumc == n))
{
printf("%d\n",n);
continue;
}
else
{
if(sumf == 0 && sums != 0 && sumc != 0) printf("%d\n",sumc);
else if(sumf != 0 && sums == 0 && sumc != 0) printf("%d\n",sumf);
else if(sumf != 0 && sums != 0 && sumc == 0) printf("%d\n",sums);
}
}
}
POJ2234
Nim游戏模板题,若每堆数量异或和为0,则先手必败,否则先手必胜。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define P system("pause");
#define B printf("Break\n");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000
int read()
{
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
}
return f * x;
}
int n;
int main()
{
while(scanf("%d",&n) != EOF)
{
int ans = 0;
for(int i = 1;i <= n;++i) ans ^= read();
puts(ans ? "Yes" : "No");
}
}
POJ2242
Code
POJ2245
Code
POJ2262
Code
POJ2301
Code
POJ2309
Code
POJ2313
Code
POJ2334
Code
POJ2346
Code
POJ2348
Code
POJ2350
Code
POJ2352
Code
POJ2381
Code
POJ2405
Code
POJ2406
Code