山东省第八届acm大学程序设计竞赛山师选拔赛第一场
(声明:标题是自己取的,如果有语法错误的话与他人无关)
-----------------------------------------------------------------------------------分割线-----------------------------------------------------------------------------------
Problem_A(大数判定2幂数)
题意:给定一个数,判断它是否是2的n次方(0<n<2^1000)
按二进制考虑的话,如果n&(n-1)==0,则这个数就是2的n次方,等于1就不是。
AC代码(JAVA版):
import java.math.BigInteger;
import java.util.*;
public class Main {
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
int T;
BigInteger N;
BigInteger ZERO = new BigInteger("0");
BigInteger ONE = new BigInteger("1");
T = scanner.nextInt();
for(int i = 0; i < T; ++i)
{
N = scanner.nextBigInteger();
BigInteger M = N.subtract(ONE);
if(N.and(M).compareTo(ZERO) == 0)
System.out.println("Yes");
else
System.out.println("No");
}
}
}
Problem_B(离散化裸题)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 2002;
bool flag[N][N];
long long x[N], y[N];
long long xx[N], yy[N];
int main()
{
int n;
scanf("%d",&n);
memset(flag, false, sizeof(flag));
for(int i = 1; i <= n; ++i)
{
scanf("%lld%lld%lld%lld",&xx[i],&yy[i],&xx[i+n],&yy[i+n]);
//输入的同时对数据进行离散化
x[2*i] = xx[i+n];
y[2*i] = yy[i+n];
x[2*i-1] = xx[i];
y[2*i-1] = yy[i];
}
//排序去重
sort(x+1, x+1+2*n);
sort(y+1, y+1+2*n);
unique(x+1, x+1+2*n);
unique(y+1, y+1+2*n);
//索引元素离散化后对应的值
for(int i = 1; i <= 2*n; ++i)
{
xx[i] = upper_bound(x+1, x+1+2*n, xx[i]) - (x+1);
yy[i] = upper_bound(y+1, y+1+2*n, yy[i]) - (y+1);
}
for(int k = 1; k <= n; ++k)
for(int i = xx[k]+1; i <= xx[k+n]; ++i) //从xx[k]+1开始
for(int j = yy[k]+1; j <= yy[k+n]; ++j)//从yy[k]+1开始
flag[i][j] = true;
long long ans = 0;
for(int i = 2; i <= 2*n; ++i)
for(int j = 2; j <= 2*n; ++j)
if(flag[i][j])
ans += (x[i]-x[i-1])*(y[j]-y[j-1]);//是y[j]-y[j-1]
cout << ans << endl;
return 0;
}
Problem_C(最长回文子串)
题意:给定一序列,输出其最长回文子序列的长度。
思路:没有思路,Manacher模板一套带走。
AC代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX = 1e6+5;
char MA[MAX*2];
int MP[MAX*2];
void Manacher(char s[], int len)
{
int l = 0;
MA[l++] = '$';
MA[l++] = '#';
for(int i = 0; i < len; ++i)
{
MA[l++] = s[i];
MA[l++] = '#';
}
MA[l] = 0;
int mx = 0, id = 0;
for(int i = 0; i < l; ++i)
{
MP[i] = mx > i ? min(MP[2*id-i], mx-i) : 1;
while(MA[i+MP[i]] == MA[i-MP[i]]) MP[i]++;
if(i+MP[i]>mx)
{
mx = i + MP[i];
id = i;
}
}
}
char s[MAX];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",s);
int len = strlen(s);
Manacher(s, len);
int ans = 0;
for(int i = 0; i < 2*len+2; ++i)
ans = max(ans, MP[i]-1);
cout << ans << endl;
}
return 0;
}
Problem_D(多重背包)
题意:有n个面值为A1,A2,..An,数量为C1,C2,..Cn的n个硬币,问他们之间互相组合能凑出多少种总面额小于m的面值
(可参照POJ的男人八题之Coins
AC代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX = 100000 + 5;
int A[105], C[105];
int DP[MAX]; //面额为A[i]的硬币在DP[i]位置用过的个数
bool vis[MAX];//能凑成的面额
int main()
{
int N, M;
while(scanf("%d%d",&N,&M) && (N||M))
{
memset(vis, false, sizeof(vis));
for(int i = 1; i <= N; ++i)
scanf("%d",&A[i]);
for(int i = 1; i <= N; ++i)
scanf("%d",&C[i]);
vis[0] = true;
for(int i = 1; i <= N; ++i)
{
memset(DP, 0, sizeof(DP));
for(int j = 1; j <= M; ++j)
{
//没有凑成过并且现在硬币的面额比要凑的面额大
if(vis[j] || j < A[i]) continue;
if(vis[j-A[i]] && DP[j-A[i]]<C[i])
{
vis[j] = true;
//cout << j << " ";
DP[j] = DP[j-A[i]] + 1;
}
}
}
//cout << endl;
int ans = 0;
for(int i = 1; i <= M; ++i)
if(vis[i]) ans++;
cout << ans << endl;
}
return 0;
}
Problem_E(思维 签到)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX = 1005;
int a[MAX];
int MIN(int a, int b, int c, int d)
{
if(a <= b && a <= c && a <= d) return 1;
if(b <= a && b <= c && b <= d) return 2;
if(c <= a && c <= b && c <= d) return 3;
if(d <= a && d <= b && d <= c) return 4;
return 0;
}
int main()
{
int n;
int x, y, z;
int ans1, ans2, ans3, ans4;
while(~scanf("%d",&n))
{
for(int i = 0; i < n; ++i)
scanf("%d",&a[i]);
bool flag = 1;
if(n < 7) flag = 0;
if(flag)
{
ans1 = ans2 = ans3 = ans4 = 0;
x = 1; y = 3; z = 5;
ans1 = a[0]; ans2 = a[2]; ans3 = a[4];
for(int i = 6; i < n; ++i)
ans4 += a[i];
while(flag)
{
if(ans1 == ans2 && ans1 == ans3 && ans1 == ans4) break;
int ans = MIN(ans1, ans2, ans3, ans4);
switch(ans)
{
case 0:
case 4: flag = 0; break;
case 1: x++;
case 2: y++;
case 3: z++; break;
}
ans1 = ans2 = ans3 = ans4 = 0;
for(int i = 0; i < x; ++i) ans1 += a[i];
for(int i = x+1; i < y; ++i) ans2 += a[i];
for(int i = y+1; i < z; ++i) ans3 += a[i];
for(int i = z+1; i < n; ++i) ans4 += a[i];
}
}
if(flag) cout << x+1 << " " << y+1 << " " << z+1 << endl;
else cout << "I am done." << endl;
}
return 0;
}
Problem_F(八进制减法)
题意:八进制减法
AC代码(C++--模拟)
/*************
Author:E6ther
*************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int main()
{
int t;
while(~scanf("%d",&t))
{
getchar();
for(int j=0;j<t;++j)
{
char a[105],b[105];
int len1=0,len2=0;
bool flag=1;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
char c;
while((c=getchar())!=' '&&c!='\n')
{
a[len1]=c-'0';
len1++;
}
a[len1]=0;
while((c=getchar())!=' '&&c!='\n')
{
b[len2]=c-'0';
len2++;
}
b[len2]=0;
/*for(int i=0;i<len1;++i)
{
printf("%d",a[i]);
}cout<<endl;
for(int i=0;i<len2;++i)
{
printf("%d",b[i]);
}cout<<endl;*/
//printf("%s %s\n",a,b);
if(len1>len2)
{
flag=1;
}
else if(len1<len2)
{
flag=0;
}
else
{
for(int i=0;i<len1;++i)
{
if(a[i]>b[i])
{
flag=1;
break;
}
else if(a[i]<b[i])
{
flag=0;
break;
}
}
}
if(flag)
{
for(int i=len2-1,j=len1-1;i>=0;--i,--j)
{
if(a[j]>=b[i])
{
a[j]=a[j]-b[i];
}
else
{
a[j]=a[j]+8-b[i];
if(a[j-1])
a[j-1]--;
else
{
int flag2=0;
for(int x=j-2;x>=0;--x)
{
if(a[x])
{
a[x]--;
flag2=1;
}
a[x+1]=7;
if(flag2) break;
}
}
}
}
}
else
{
for(int i=len1-1,j=len2-1;i>=0;--i,--j)
{
if(a[i]<=b[j])
{
b[j]=b[j]-a[i];
}
else
{
b[j]=b[j]+8-a[i];
if(b[j-1])
b[j-1]--;
else
{
int flag2=0;
for(int x=j-2;x>=0;--x)
{
if(b[x])
{
b[x]--;
flag2=1;
}
b[x+1]=7;
if(flag2) break;
}
}
}
}
}
bool flag1=0;
if(flag)
{
for(int i=0;i<len1;++i)
{
if(a[i]) flag1=1;
if(flag1)
printf("%d",a[i]);
}
if(!flag1) cout<<"0";
}
else
{
cout<<"-";
for(int i=0;i<len2;++i)
{
if(b[i]) flag1=1;
if(flag1)
printf("%d",b[i]);
}
}
cout<<endl;
}
}
return 0;
}
AC代码(JAVA):
import java.math.BigInteger;
import java.util.*;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
int T;
Scanner scanner = new Scanner(System.in);
T = scanner.nextInt();
BigInteger N, M, X, Y;
for(int i = 0; i < T; ++i)
{
N = scanner.nextBigInteger();
M = scanner.nextBigInteger();
X = new BigInteger(N.toString(),8);
Y = new BigInteger(M.toString(),8);
X = X.subtract(Y);
System.out.println(X.toString(8));
}
}
}
Problem_G(模拟?)
题意:给你n个数,输出对他们进行第一次快速排序后的结果。不知道快速排序的话,自己去搜(其实不知道也没关系,题目里已经给出了排序的方式了,按照它的来就是了)。
AC代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX = 10005;
int a[MAX];
void solve(int n)
{
int tem = a[0];
int l = 0, r = n;
while(l <= r)
{
for(--r; l <= r; --r)
{
if(a[r] < tem)
{
a[l] = a[r];
break;
}
}
for(++l; l <= r; ++l)
{
if(a[l] > tem)
{
a[r] = a[l];
break;
}
}
}
a[--l] = tem;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(a, 0, sizeof(a));
for(int i = 0; i < n; ++i)
scanf("%d",&a[i]);
solve(n);
for(int i = 0; i < n; ++i)
{
if(i) cout << " ";
cout << a[i];
}
cout << endl;
}
return 0;
}
Problem_H(大素数判定)
题意:给你n个数,输出他们中素数的个数。要用到Miller-rabin算法,套个模板就好了。
AC代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <ctime>
using namespace std;
const int S = 8;//随机算法判定次数,一般8~10次就够了
//计算ret = (a*b)%c a, b, c < 2^63
long long mult_mod(long long a, long long b, long long c)
{
a %= c;
b %= c;
long long ret = 0;
long long tem = a;
while(b)
{
if(b & 1)
{
ret += tem;
if(ret > c) ret -= c;//直接取模慢很多
}
tem <<= 1;
if(tem > c) tem -= c;
b >>= 1;
}
return ret;
}
//计算 ret = (a^n) % mod
long long pow_mod(long long a, long long n, long long mod)
{
long long ret = 1;
long long tem = a % mod;
while(n)
{
if(n & 1) ret = mult_mod(ret, tem, mod);
tem = mult_mod(tem, tem, mod);
n >>= 1;
}
return ret;
}
// 通过 a^(n-1)=1(mod n)来判断n是不是素数
// n-1 = x * 2^t 中间使用二次判断
// 是合数返回true,不一定是合数返回false
bool check(long long a, long long n, long long x, long long t)
{
long long ret = pow_mod(a, x, n);//a^x % n
long long last = ret;
for(int i = 1; i <= t; ++i)//进行t次(a^x % n)^2 % n
{
ret = mult_mod(ret, ret, n);
if(ret == 1 && last != 1 && last != n - 1) return true;//合数
last = ret;
}
if(ret != 1) return true;
return false;//不一定是合数
}
//**************************************************
// Miller_Rabin算法
// 是素数返回true,(可能是伪素数)
// 不是素数返回false
//**************************************************
bool Miller_Rabin(long long n)
{
if(n < 2) return false;
if(n == 2) return true;
if( (n&1) == 0) return false;//偶数
long long x = n - 1;
long long t = 0;
while( (x&1) == 0) //将n分解为x*2^t;
{
x >>= 1;
t++;
}
srand( time(NULL));
for(int i = 0; i < S; ++i)
{
long long a = rand()%(n-1) + 1;//产生随机数a(并控制其范围在1 ~ n-1之间)
if(check(a, n, x, t))//是合数
return false;
}
return true;
}
int main()
{
int t, ans;
long long tem;
scanf("%d",&t);
ans = 0;
while(t--)
{
scanf("%lld",&tem);
if(Miller_Rabin(tem)) ans++;
}
cout << ans << endl;
return 0;
}
因为预计这周周六会进行第二场选拔赛,本打算完了后两场一块写,可是那个ZZ说我不写博客直接给他代码,心里不踏实,所以只好牺牲自己的睡眠时间来写着“十分有用”的博客了。 祝你生活愉快。:)
(你还嫌我写的太敷衍?我这暴脾气。
另外,搬机房了,新机房更宽敞,条件也更好点(?,但是并不是很开心啊,虽然只在五楼呆了一学期多点吧,但就这样突然离开还是有些不舍的(大概是因为那里承载了太多的--几乎是目前的大学的全部回忆吧,不去纠结了,太重感情也不是件好事哦,哈哈。