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入门题。

[f[x][y] = max(f[x+1][y],f[x+1][y+1])+a[x][y] ]

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
",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
",(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.
",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.
",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
",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);
		else{
			if(a == 0) printf("%d
",b);
			else if(b == 0) printf("%d
",c);
			else printf("%d
",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
",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,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
");
        else printf("%d %d
",(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
",s-k,s+k);	
	}
	return 0;
} 
原文地址:https://www.cnblogs.com/excellent-zzy/p/12764047.html