这次比赛5/12,感觉还是实力不太行,几道题目感觉可以写但是没写出来,赛后看题解也补完了所有的题目。这里正式记录一下,方便以后的回顾。官方题解
A 解锁专家
找规律。藏头诗,根据诗的每个首字母可得到提示。同时还是个大数,使用Java解决
import java.util.Scanner;
import java.math.BigInteger;
public class Main {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()) {
int n=scanner.nextInt();
if(n==1)
System.out.println(1);
else {
if(n==2)
System.out.println(2);
else {
if(n==3) {
System.out.println(4);
} else {
BigInteger[] num = new BigInteger[101];
num[1]=BigInteger.ONE;
num[2]=BigInteger.valueOf(2);
num[3]=BigInteger.valueOf(4);
for(int i=4;i<=100;i++) {
num[i]=BigInteger.ZERO;
num[i]=BigInteger.valueOf(2).multiply(num[i-1]);
num[i]=num[i].subtract(num[i-3]);
}
System.out.println(num[n].mod(BigInteger.valueOf(433494437)));
}
}
}
}
}
}
B 麻烦的杰西
一开始以为求最长连续递增子序列,然后WA到自闭......因为不是递增的序列也可以,所以换种思路所以对于每个位置做一个记录。l[i]表示位置i往左能找到的 不小于当前位置高度的 最长连续的 最左端的位置。如何更新l[i],对于每个位置i,假设h[i]<=h[l[i]-1],说明最左端的左边位置高度不小于当前位置i的高度,所以l[i]就可以沿用l[i]-1的l[],即:l[i]=l[l[i]-1]。r[i]同理可得。这里是使用栈的特性进行记录序列的头和尾,遍历一遍即可
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a[1000005], h[1000005];
int main() {
int n;
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; i++) {
scanf("%lld", &h[i]);
a[i] = i;
}
stack<ll>st;
h[0] = -1000;
h[n + 1] = -999;
st.push(0);
ll ans = 0, t = 0;
for (int i = 1; i <= n + 1; i++) {
while (h[st.top()] > h[i]) {
ll index = st.top();
st.pop();
ll cnt = a[i - 1] - a[st.top()];
if (ans < cnt * h[index]) {
t = h[index];
ans = cnt * h[index];
}
}
st.push(i);
}
printf("%lld %lld\n", t, ans);
}
return 0;
}
C 最大模数
这就直接贴题解了,简单来说枚举前几个数寻找规律,然后根据奇偶性判定输出不同结果
通过二项式定理列出n取1~5的情况:
% a²后有:
显然,对n为偶数的情况,结果都是2。对n为奇数的情况,结果为2 * n * a。
此时问题转化为 求2 * n * a % ( a² ) 的最大值。
初步判断,知道2 * n * a = a² 时n的取值,把n-1代入上式,结果就是最大值。
进一步,通过化简2 * n * a = a² ,可以得到 n = a / 2。 故需要再考虑a的奇偶性:
①、当 a 为奇数的时候
由于 2 * n * a = 2 * (a / 2) * a < a² , 所以不需要取n-1,此时Ra就是最大模数了。
最大模数就是 2 * ( a - 1 ) / 2 * a = a² - a 。
②、当 a 为偶数的时候
由于 2 * n * a = 2 * (a / 2) * a = a² , 此时Ra = 0,所以取n-1,即n = a / 2 - 1。
最大模数就是 2 * a * ( a / 2 - 1 ) = a² - 2 * a 。
#include<bits/stdc++.h>
using namespace std;
vector<int> p1,p2;
int main() {
long long n;
while(~scanf("%lld",&n)) {
if(n%2==0)
printf("%lld\n",n*n-2*n);
else
printf("%lld\n",n*n-n);
}
return 0;
}
D 米多利亚
传送门
对于这种字符串交换找最小字典序的字符串题目类型,需要先观察对于'0' , ' 1' , '2' 这三种字符哪一种是特殊的,特殊体现在就是在三者之间,只有自己才有的特性,发现相邻的 '01','10','12','21' 可以任意交换成 '10','01','21','12'。
也就是'1'字符可以和'0','2'任意交换,同时只有'0','2'两者之间是不可交换的。举个例子,'102' 可以交换成'012','021'。无论怎么交换'0'和'2'的相对位置都是不能改变的。所以答案就是,在所有'0','2'相对位置不变的情况下,把字符串中所有的'1’都放在第一个'2'前面。
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
while(cin>>s) {
int numone=0;
for(int i=0;i<s.length();i++) {
if(s[i]=='1')
numone++;
}
int start=0;
while(s[start]!='2')
start++;
int numzero=0;
for(int i=0;i<start;i++) {
if(s[i]=='0')
numzero++;
}
string ans="";
while(numzero--)
ans+="0";
while(numone--)
ans+="1";
for(int i=start;i<s.length();i++) {
if(s[i]=='2'||s[i]=='0')
ans+=s[i];
}
cout<<ans<<endl;
}
return 0;
}
E 一步两步是魔鬼的步伐
二分法求取最大最小值。这题比赛的时候好像出锅了,然后果断没看
#include<bits/stdc++.h>
using namespace std;
const int maxn=200011;
int L, N, M;
int a[maxn],vis[maxn];
bool check(int m) {
int cnt=0, pre=0;
for(int i=1; i<=N; ++i) vis[i]=0;
for(int i=1; i<=N; ++i) {
if(a[i]-pre<m) cnt++;
else pre=a[i], vis[i]=1;
}
pre=L;
for(int i=N; i; --i) {
if(!vis[i]) continue;
if(pre-a[i]<m) cnt++;
else break;
}
return cnt<=M;
}
int main() {
while(cin>>L>>N>>M) {
for(int i=1; i<=N; ++i)
scanf("%d",&a[i]);
sort(a+1,a+1+N);
int l=1, r=L+1;
while(l<r) {
int m=(l+r)/2;
if(check(m)) l=m+1;
else r=m;
}
printf("%d\n", l-1);
}
}
F 参赛
暴力打表,计算出每种符合的情况
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1011;
bool vis1[MAXN];
bool vis2[MAXN];
void init() {
memset(vis1,false,sizeof(vis1));
for(int i=1;i<=100;i++) {
int temp=i*3;
for(int j=1;j<=i;j++)
vis1[temp+j]=true;
}
memset(vis2,false,sizeof(vis2));
for(int i=1;i<=30;i++) {
int temp=i*10;
for(int j=1;j<=i;j++)
vis2[temp+j]=true;
}
}
int main() {
init();
int n;
while(~scanf("%d",&n)) {
if(vis1[n]) {
if(vis2[n])
puts("All");
else
puts("First");
} else {
if(vis2[n])
puts("Second");
else
puts("No");
}
}
return 0;
}
G 数数有多少个水坑
经典的求取联通块问题
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1011;
int n,m;
int next1[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
bool vis[MAXN][MAXN];
int num[MAXN][MAXN];
void DFS(int x,int y) {
for(int i=0;i<4;i++) {
int x1=x+next1[i][0];
int y1=y+next1[i][1];
if(x1<0||x1>=n||y1<0||y1>=m)
continue;
else {
if(vis[x1][y1]||num[x1][y1]==0)
continue;
else {
vis[x1][y1]=true;
DFS(x1,y1);
}
}
}
}
int main() {
while(~scanf("%d%d",&n,&m)) {
memset(vis,false,sizeof(vis));
memset(num,0,sizeof(num));
getchar();
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
char c;
scanf("%c",&c);
if(c=='j'||c=='e'||c=='s'||c=='i')
num[i][j]=1;
}
getchar();
}
int ans=0;
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
if(num[i][j]&&!vis[i][j]) {
vis[i][j]=true;
DFS(i,j);
ans++;
}
}
}
printf("%d\n",ans);
}
return 0;
}
H 你相信爱情吗
初看以为约瑟夫环,细品一下发现哦原来还是GCD,可惜可惜
#include<bits/stdc++.h>
using namespace std;
int main() {
int t;
while(~scanf("%d",&t)) {
while(t--) {
long long n,m;
scanf("%lld%lld",&n,&m);
long long z=__gcd(n,m);
long long temp=n/z;
if(temp>=n)
printf("%lld\n",temp);
else
puts("-1");
}
}
return 0;
}
I 师姐我想要红包
师姐我也想要红包。哦实验室里我最老,那打扰了。这乍一看以为MST,细品发现,状压裸题。回去补知识点了可惜可惜
#include<bits/stdc++.h>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn=1005;
typedef long long ll;
int n;
const int inf=0x3f3f3f3f;
struct points
{
double x,y;
}a[15];
double getlen(int i,int j)
{
return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
double dis[15][15];
double dp[1<<15][15];
int main()
{
while(cin>>n) {
a[0].x=0;a[0].y=0;
for(int i=1;i<=n;++i)
cin>>a[i].x>>a[i].y;
for(int i=0;i<=n;++i)
for(int j=i+1;j<=n;++j)
dis[i][j]=dis[j][i]=getlen(i,j);
n++;
for(int i=0;i <= 1<<n;++i) {
for(int j=0;j<=n;++j)
dp[i][j]=inf;
}
dp[1][0]=0;
for(int i=1;i< 1<<n;++i) {
for(int j=0;j<n;++j)
if(i>>j&1) {
for(int k=0;k<n;++k) {
if((i^1<<j)>>k&1)
dp[i][j]=min(dp[i][j],dp[i^1<<j][k]+dis[k][j]);
}
}
}
double ans=inf;
for(int i=0;i<n;++i)
ans=min(ans,dp[(1<<n)-1][i]);
printf("%.2f\n",ans);
}
return 0;
}
J 试试划水
老题型了,老解法了,直接贴代码
#include<bits/stdc++.h>
char ch[100000+5];
int num1[100000+5];
int num2[100000+5];
int main() {
int t;
scanf("%d",&t);
while(t--) {
memset(num1,0,sizeof(num1));
memset(num2,0,sizeof(num2));
int len,ans=0;
scanf("%s",ch);
len=strlen(ch);
for(int i=len-1;i>=0;i--) {
num2[i]=num2[i+1];
if(ch[i]=='U')
num2[i]++;
}
for(int i=0;i<len;i++) {
if(i!=0)
num1[i]=num1[i-1];
if(ch[i]=='Z')
num1[i]++;
}
long long cnt=0;
for(int i=0;i<len;i++) {
if(ch[i]=='Q')
cnt+=num1[i]*num2[i];
}
printf("%lld\n",cnt);
}
return 0;
}
K 钟Sir的任务
考虑贪心,每次从右往左将较小的字符往左移即可。暴力模拟即可解决问题
#include<bits/stdc++.h>
using namespace std;
const int MAXN=111;
vector<int> p;
bool vis[MAXN];
int main() {
int t;
while(~scanf("%d",&t)) {
while(t--) {
memset(vis,false,sizeof(vis));
int n;
scanf("%d",&n);
p.clear();
p.resize(n);
for(int i=0;i<n;i++)
scanf("%d",&p[i]);
if(n==1) {
printf("%d\n",p[0]);
continue;
}
int cnt=0,m=n-1,temp=n;
while(temp--) {
bool flag=false;
for(int i=n-1;i>=0;i--) {
if(p[i]<p[i-1]&&!vis[i-1])
vis[i-1]=true,swap(p[i],p[i-1]),cnt++,flag=true;
if(cnt==m)
break;
}
if(!flag)
break;
if(cnt==m)
break;
}
for(int i=0;i<n;i++) {
if(i==0)
printf("%d",p[i]);
else
printf(" %d",p[i]);
}
printf("\n");
}
}
return 0;
}
L JAVA_Xin的小心思
考虑贪心,先求取不压缩的值之和,然后按照压缩量排序,每次从大到小依次减去压缩量,直到符合条件为止。
#include<bits/stdc++.h>
using namespace std;
vector<long long> p;
int main() {
int n;
long long m;
while(~scanf("%d%lld",&n,&m)) {
p.clear();
long long suma=0,sumb=0;
for(int i=0;i<n;i++) {
long long a,b;
scanf("%lld%lld",&a,&b);
suma+=a,sumb+=b;
p.push_back(a-b);
}
sort(p.begin(),p.end());
if(sumb>m)
puts("-1");
else {
bool flag=false;
int cnt=0;
for(int i=n-1;i>=0;i--) {
if(suma<=m) {
flag=true;
printf("%d\n",cnt);
break;
}
cnt++;
suma-=p[i];
}
if(!flag) {
if(suma<=m)
printf("%d\n",cnt);
else
puts("-1");
}
}
}
return 0;
}