文章目录
题目集地址 ICPC南宁2017
F The Chosen One 数学规律
题目地址F - The Chosen One
题目大意:给出1-n,每次删除第2,4,6…位置上的数,问到最后剩下的数是谁?
思路:有一个规律,每次剩下的数都是不大于n的2的幂次,不过要用JAVA的大数来做
AC代码:
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int t = input.nextInt();
String string;
BigInteger TWO = new BigInteger("2");
for(int i = 1;i<=t;i++)
{
string = input.next();
BigInteger a = new BigInteger(string);
if(a.equals(TWO))
{
System.out.println(2);
continue;
}
BigInteger b = TWO;
while(b.compareTo(a)<0)
{
b=b.multiply(TWO);
}
if(b.equals(a))
System.out.println(b.toString());
else {
System.out.println(b.divide(TWO).toString());
}
}
}
}
H The Game of Life 元胞自动机类问题
题目地址H - The Game of Life
题目大意:给出n*m的字符型矩阵,’.'表示不存在细胞,’#‘表示存在。
- 细胞能够分裂的几种情况是:
- 若当前活着的细胞旁边(8联通)存在的活着的细胞数小于2,则当前细胞死亡;
- 若当前活着的细胞旁边存在的活着的细胞数等于2,则当前细胞能够进行到下一次的分裂;
- 若当前活着的细胞旁边存在的活着的细胞数等于3,则当前位置新生成一个细胞;
- 若当前的细胞旁边存在的活着的细胞数大于3,则当前细胞死亡;
输出:在分裂321次过程中,第几次细胞的数目达到最大,数目最大是多少,和第321次细胞的数量
思路:暴力模拟
AC代码:
#include<bits/stdc++.h>
using namespace std;
int t,n,m;
int a[700][700],b[700][700];//相互作为临时数组
int getAround(bool flag,int x,int y) {//判断当前位置周围
int sum=0;
if(flag) {
sum-=a[x][y];
for(int i=-1; i<=1; i++)
for(int j=-1; j<=1; j++)
sum+=a[x+i][y+j];
} else {
sum-=b[x][y];
for(int i=-1; i<=1; i++)
for(int j=-1; j<=1; j++)
sum+=b[x+i][y+j];
}
return sum;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >>t;
while(t--) {
cin >>n>>m;
memset(a,0,sizeof(a));//初始化
memset(b,0,sizeof(b));//同上
char ch;
int sum=0,mx=0,pos=0,d=350,u=350+5,l=350,r=350+5;
//初始化边界
for(int i=0; i<n; i++)
for(int j=0; j<m; j++) {
cin >>ch;
if(ch=='#')
a[350+i][350+j]=1,sum++,mx++;
}
for(int i=1; i<=321; i++) {
sum=0;
if(i&1) {
for(int i=d-1; i<=u+1; i++)//只判断涉及到的范围
for(int j=l-1; j<=r+1; j++) {
int res=getAround(1,i,j);
b[i][j]=a[i][j];
if((res<2||res>3)&&a[i][j])b[i][j]=0;
else if(res==3&&!a[i][j])b[i][j]=1;
sum+=b[i][j];
if(b[i][j]) {//如果可以拓展
if(i==d-1)d--;
else if(i==u+1)u++;
if(j==l-1)l--;
else if(j==r+1)r++;
}
}
} else {
for(int i=d-1; i<=u+1; i++)//只判断涉及到的范围
for(int j=l-1; j<=r+1; j++) {
int res=getAround(0,i,j);
a[i][j]=b[i][j];
if((res<2||res>3)&&b[i][j])a[i][j]=0;
else if(res==3&&!b[i][j])a[i][j]=1;
sum+=a[i][j];
if(a[i][j]) {
if(i==d-1)d--;
else if(i==u+1)u++;
if(j==l-1)l--;
else if(j==r+1)r++;
}
}
}
if(sum>mx)pos=i,mx=sum;
}
cout <<pos<<" "<<mx<<" "<<sum<<endl;
}
return 0;
}
I Rake It In 对抗搜索
题目地址I - Rake It In
题目大意:有一个总分数,给出一共4×4矩阵,A和B对矩阵轮流操作,A先操作,每次操作选择一个2×2的矩阵,统计矩阵元素和加在总分数上,然后将这个2×2矩阵逆时针旋转90度,一共进行k轮,也就是2k次操作,A的目标是使得总分数最大,B的目标是使得总分数最小,计算两人在最优策略下最后获得的总分数。
思路:我们一开始思路错了,我们认为对于A来说每次操作选择最大的2*2的网格即可,B就选择最小的操作,这样就会遇到一个问题,比如在当下有好几个相同的最大值,应该操作哪一个?
正确思路应该是总共是先后手一共2×k轮,用DFS回溯,从最后一次后手起始加和,因为最后一次后手不影响其他的,一直回溯回去。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int maze[5][5],k;
int sum(int x,int y)
{
return maze[x][y]+maze[x+1][y]+maze[x][y+1]+maze[x+1][y+1];
}
void clockwise(int x,int y)
{
int t = maze[x][y];
maze[x][y]=maze[x+1][y];
maze[x+1][y]=maze[x+1][y+1];
maze[x+1][y+1]=maze[x][y+1];
maze[x][y+1]=t;
}
void anticlockwise(int x,int y)
{
int t = maze[x][y];
maze[x][y]=maze[x][y+1];
maze[x][y+1]=maze[x+1][y+1];
maze[x+1][y+1]=maze[x+1][y];
maze[x+1][y]=t;
}
int dfs(int p)
{
if(p==2*k)
{
int minn=INF;
for(int i =1;i <=3;i++)
{
for(int j = 1;j <= 3;j++)
{
clockwise(i,j);
minn=min(minn,sum(i,j));
anticlockwise(i,j);
}
}
return minn;
}
if(p&1)
{
int maxn=0;
for(int i = 1;i <=3;i++)
{
for(int j =1; j<=3;j++)
{
anticlockwise(i,j);
maxn = max(maxn,sum(i,j)+dfs(p+1));
clockwise(i,j);
}
}
return maxn;
}
else
{
int minn=INF;
for(int i = 1;i <=3;i++)
{
for(int j =1; j<=3;j++)
{
anticlockwise(i,j);
minn = min(minn,sum(i,j)+dfs(p+1));
clockwise(i,j);
}
}
return minn;
}
}
int main()
{
// freopen("in.txt","r",stdin);
// int t = 1;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&k);
for(int i =1;i <= 4;i++)
{
for(int j = 1;j <=4;j ++)
{
scanf("%d",&maze[i][j]);
}
}
printf("%d\n",dfs(1));
}
return 0;
}
J Rearrangement 数学规律
题目地址J Rearrangement
题目大意:给出2行n列的一个数组,完全重排列,问能否保证任意相邻的两个数的和不被3整除
思路:把所有的数字对3取余,然后就剩下3个数字,0,1,2,然后就是1和2不能放一起,0和0不能放一起,找规律即可,我们是按照1和2的个数是奇偶分类的,比较复杂,后面贴一个大佬的按照0的个数分类的代码。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N = 2e5+6;
int cnt[3];
void solve()
{
for(int i = 0;i <= 2;i ++)
{
cnt[i]=0;
}
int n;
scanf("%d",&n);
for(int i =1;i <= 2*n;i++)
{
int t;
scanf("%d",&t);
cnt[t%3]++;
}
if(n==1)
{
if(cnt[0]==1)
printf("YES\n");
else if(cnt[1]==2||cnt[2]==2)
{
printf("YES\n");
}
else
printf("NO\n");
}
else if(cnt[0]>n)
{
printf("NO\n");
}
else if((cnt[1]&1)&&(cnt[2]&1))
{
if(cnt[0]>=2)
printf("YES\n");
else
{
printf("NO\n");
}
}
else if(!(cnt[1]&1)&&!(cnt[2]&1))
{
if(cnt[1]==0||cnt[2]==0)
{
printf("YES\n");
}
else if(cnt[0]>3)
printf("YES\n");
else
{
printf("NO\n");
}
}
else
{
if(cnt[1]==0||cnt[2]==0)
{
printf("YES\n");
}
else if(cnt[0]>2)
printf("YES\n");
else
{
printf("NO\n");
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
// int t = 1;
int t;
scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}
//这是按照0分类的,比我们的简单多了
#include <bits/stdc++.h>
using namespace std;
int n;
int arr[3];
void input()
{
scanf("%d",&n);
CLR(arr, 0);
for (int i = 0; i < 2 * n; i++)
arr[read() % 3]++;
}
bool solve()
{
if (arr[0] > n) return false;
if (arr[0] <= 1 && arr[1] && arr[2]) return false;
if (arr[0] == 2 && (arr[1] % 2 == 0) && (arr[2] % 2 == 0)) return false;
return true;
}
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
input();
puts(solve() ? "YES" : "NO");
}
}
L Twice Equation 数学打表找规律
题目地址L - Twice Equation
题目大意:给出一个正整数L,找到一个最小的不小于L的整数n,使得存在一个正整数m满足等式2m(m+1)=n(n+1)
思路:我们是打表的 然后找到了一个规律a[i]=(a[i-1]+a[i-2])*5+4-a[i-3]
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static BigInteger a[]= new BigInteger[2010];
public static void main(String[] args) {
// TODO Auto-generated method stub
init();
Scanner inputScanner=new Scanner(System.in);
int t = inputScanner.nextInt();
for(int i = 1;i <= t;i++)
{
String string = inputScanner.next();
BigInteger lBigInteger = new BigInteger(string);
int l = 0;
int r = 2000;
if(lBigInteger.compareTo(a[l])<=0) {
System.out.println(a[l].toString());
}
else {
while(l<r)
{
int mid = (l+r)/2;
if(a[mid].compareTo(lBigInteger)>=0)
{
r=mid;
}
else {
l=mid+1;
}
}
System.out.println(a[l].toString());
}
}
}
static void init() {
a[0]=new BigInteger("3");
a[1]=new BigInteger("20");
a[2]=new BigInteger("119");
for(int i=3;i<=2000;i++)
{
a[i]=(a[i-1].add(a[i-2])).multiply(BigInteger.valueOf(5))
.add(BigInteger.valueOf(4)).subtract(a[i-3]);
}
}
}