poj杂题选讲
poj杂题选讲
poj1147:
根据最后一列,可以确定答案中0/1的个数,同样第一列也确定了,因为每次操作之后得到的矩阵都是排过序的,不妨考虑一下把最后一列移到第一列,这样可以得到最后一列与第一列排序的对应关系,然后根据这个对应关系就可以知道每一行经过排序会发生什么变化,这样不断递推就可以求出整个矩阵了。由于只需要第一行,输出即可。
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 3e3 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
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];
puts("");
return 0;
}
poj1163:
数字三角形,dp入门题。
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 105;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
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
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 2e5 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
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^k_n\) 种排列中的排名的字典序。
这大概是个高中数学的排列组合问题。得到的排列是 \(x_1,x_2,...,x_k\),按位考虑即可,对于第\(i\)个元素,有\((x_i-1)A_{n-i}^{k-i}\)个,当然去个重。
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 25 + 5;
using namespace std;
inline LL read() {
LL s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
LL fac[N],a[N],T;
LL A(LL n,LL m){
if(n < m) return 0;
return fac[n] / fac[n - m];
}
void init(){
fac[0] = 1;
for(LL i = 1;i <= 12;++i) fac[i] = fac[i - 1] * i;
return ;
}
void solve(){
for(LL j = 1;j <= T;++j){
LL n = read(),k = read(),ans = 0;
for(LL i = 1;i <= k;++i) a[i] = read();
for(LL i = 1;i <= k;++i){
ans += (a[i] - 1) * A(n - i,k - i);
for(int l = i + 1;l <= k;++l) if(a[l] > a[i]) a[l]--;
}
printf("Variace cislo %lld ma poradove cislo %lld.\n",j,ans + 1);
}
}
int main(){
T = read();
init();
solve();
return 0;
}
poj2215:
题目大意:给定一个矩形,内部每个点有权值,多次询问一个子矩形内部权值和。
二维前缀和了解一下
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 2e3 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int a[N][N],sum[N][N];
void init(){
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];
}
void solve(){
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("");
}
int main(){
int T = read();
while(T--){
init();
solve();
}
}
poj2229:
题目大意:求一个数 \(n\) 按照2的幂次拆分的方案数。
如果\(i\)是奇数,那么在所有的系列中一定含有一个1,把这个1减掉,就和$i-1¥的对应相等。
如果\(i\)是偶数,那么每一项要么都是2以上的数字,要么就一定含有至少两个1。第一种情况,都含有两个1那么就减掉,那么就等于\(i-2\)对应的值,还有就是全部是2的整数倍,那么不妨直接把2看成1,那是不是相当于数字减少了一半,那么就等于\(i/2\)对应的值了。
\(O(n)\)递推就完事了
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int mod = 1000000000;
const int N = 2e6 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int f[N];
int main(){
int n = read();
f[1] = 1,f[2] = 2;
for(int i = 3;i <= n; i++){
if(i & 1) f[i] = f[i-1];
else f[i] =(f[i-1] + f[i>>1]) % mod;
}
printf("%d\n",f[n]);
return 0;
}
poj2232:
若只有一种手势或有三种手势,则都可以赢,若有两种手势,则克其的能赢。
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 2e5 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int n;
char ch[2];
int main(){
while(scanf("%d",&n)!=EOF){
int a = 0,b = 0,c = 0;
for(int i = 0; i < n; i++ ){
scanf("%s",ch);
if(ch[0] == 'C') a++;
if(ch[0] == 'S') b++;
if(ch[0] == 'F') c++;
}
if((a == 0 && b == 0 && c != 0)||(a == 0 && c == 0 && b != 0)||(b == 0 && c == 0 && a != 0)||(a != 0 && b != 0 && c != 0))printf("%d\n",n);
else{
if(a == 0) printf("%d\n",b);
else if(b == 0) printf("%d\n",c);
else printf("%d\n",a);
}
}
return 0 ;
}
poj2234:
经典nim游戏,异或值为不为0则先手胜出。
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 2e5 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int n;
int main(){
while(scanf("%d",&n)!=EOF){
int ans = 0;
for(int i = 1;i <= n;i++){
int a = read();
ans ^= a;
}
if(ans) puts("Yes");
else puts("No");
}
return 0;
}
poj2242
题意:给定圆上3点,求圆的周长
思路分析:外接圆半径\(r = (a*b*c)/(4*S)\),其中\(a,b,c\)为边长,S为三角形面积,\(L = 2*\pi*r\)
或者是利用圆心为中垂线的交点,求出圆心,然后再求半径也可以。
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 2e5 + 5;
#define eps 1e-6
#define pi 3.141592653589793
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int main(){
double x1,x2,x3,y1,y2,y3;
while(scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3) != EOF){
double cc = x2-x1,d = y2-y1,e = x3-x1,f = y3-y1;
double s = fabs(cc*f - d*e);
s = s/2;
double a = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
double b = sqrt((x1-x3)*(x1-x3) + (y1-y3)*(y1-y3));
double c = sqrt((x2-x3)*(x2-x3) + (y2-y3)*(y2-y3));
double r = a*b*c/4/s;
printf("%0.2lf\n",2*pi*r);
}
return 0;
}
poj2245
问题大意:给你k个数(递增顺序),从中选择6个数,打印所有的组合方案。k=0表示输入结束,打印时每两个数之间才有空格,并且每个测试之间有一个空行。
DFS即可
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
const int N=14;
int vis[N],ans[N],a[N],n;
void dfs(int i,int k) {
if(k == 6){
printf("%d",ans[0]);
for(int j = 1;j < 6;j++) printf(" %d",ans[j]);
puts("");
return;
}
for(;i < n;i++)
if(!vis[i]){
vis[i] = 1;
ans[k] = a[i];
dfs(i + 1,k + 1);
vis[i] = 0;
}
}
int main(){
bool flag = 0;
while(scanf("%d",&n)!=EOF&&n){
for(int i=0;i<n;i++) a[i] = read();
if(flag) puts("");
flag = 1;
memset(vis,0,sizeof(vis));
dfs(0,0);
}
return 0;
}
poj2262:
题目大意:给你一个数n,拆分成两个奇素数相加的形式,另这两个素数的距离最大
思路:从三开始枚举奇数,判断数\(i\)和\(n-i\)是否都为素数,若为素数则输出结果。
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 1000000 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int pn[N];
void init(){
for(int i = 2; i <= N; i++) pn[i] = 1;
for(int i = 2; i <= N; i++) if(pn[i]) for(int j = i+i; j <= N; j += i) pn[j] = 0;
}
int main(){
int n;
init();
while(~scanf("%d",&n) && n){
for(int i = 3; i <=n/2; i+=2){
if(pn[i] && pn[n-i]){
printf("%d = %d + %d\n",n,i,n-i);
break;
}
}
}
return 0;
}
poj2301:
值得注意的是两个数相加或相减的奇偶性是一致的
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 2e5 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int main(){
int n = read();
while(n--){
int a = read(),b = read();
if((a < b) || (a%2==0&&b%2==1)||(b%2==0&&a%2==1)) printf("impossible\n");
else printf("%d %d\n",(a+b)/2,(a-b)/2);
}
}
poj2309:
找规律即可,可以理解为二分查找的过程,我是直接找规律,代码简单
Code
#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 2e5 + 5;
using namespace std;
inline int read() {
int s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-')
w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
int main(){
int n = read();
while(n--){
int s = read();
int k=s&(-s);
k--;
printf("%d %d\n",s-k,s+k);
}
return 0;
}