前言
个人认为难度:
T1(难在读题)<T4(代码较长,思路简单)<T2(有一定的思维量,较为经典的要排序的 01 背包问题)<T5(广搜)<T3(难在读题 + 坑点较多的模拟)<T6(线性 DP)<T7(紫题劝退)
T1
\(AC\ \ on\ \ 2021.06.11\)
这题是来考语文的吗?
题目老长,愣是看了半天才看懂。
读懂题后:这不就是给一串数处理之后加在一起咩??
处理也很简单 (事实证明这道题最难的地方在读题),直接看灯是什么颜色:如果是绿的就变为 \(0\),如果是红的就不变,如果是黄的就加上 \(r\)。
结果打完之后代码 CE 了后来我才发现 time
是 c++ 的关键词,无语……
\(Code\)
#include<bits/stdc++.h>
using namespace std;
int n,a,b,r,y,g,Time;
int main(){
scanf("%d %d %d %d",&r,&y,&g,&n);
for(int i=1;i<=n;i++){
scanf("%d %d",&a,&b);
if(!a||a==1) Time+=b;
else if(a==2) Time+=b+r;
}
printf("%d",Time);
return 0;
}
T2
\(AC\ \ on\ \ 2021.06.13\)
吃石头可海星。
背包,考点是怎么排序。
假设要吃两个石头 \(x\) 和 \(y\),先吃 \(x\) 比先吃 \(y\) 好。
设 \(first\) 为石头的初始能量值,\(lost\) 为每秒石头会浪费的能量值,\(time\) 为吃一块石头要用的时间。
为了方便我们不考虑石头能量值流完的情况。
那么先吃 \(x\) 的表达式为:
\[energy1=x_{first}+y_{first}-x_{time}\times y_{lost} \]先吃 \(y\) 的表达式为:
\[energy2=y_{first}+x_{first}-y_{time}\times x_{lost} \]我们知道 \(energy1>energy2\)
代入原式:
\[x_{first}+y_{first}-x_{time}\times y_{lost}>y_{first}+x_{first}-y_{time}\times x_{lost} \]把相同的地方抵消了就变成:
\[-x_{time}\times y_{lost}>-y_{time}\times x_{lost} \]把负号搞掉:
\[x_{time}\times y_{lost}<y_{time}\times x_{lost} \]嗯,式子出来了,排序后再用一个 \(01\) 背包,over。
注意两点:
-
背包 dp 初始化是 \(128\)(因为这代表的是时间点要算还剩多少能量值),只有 \(dp_0\) 初始化为 \(0\);
-
开
long long
。
\(Code\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,ans,dp[10005];
struct rock{int t,lost,first;}a[105];
bool cmp(rock x,rock y){return x.t*y.lost<y.t*x.lost;}
signed main(){
scanf("%d",&T);
for(int r=1;r<=T;r++){
ans=0;
memset(dp,128,sizeof(dp));
dp[0]=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld %lld %lld",&a[i].t,&a[i].first,&a[i].lost);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
for(int j=10000;j>=a[i].t;j--){
dp[j]=max(dp[j],dp[j-a[i].t]+a[i].first-(j-a[i].t)*a[i].lost);
}
}
for(int i=0;i<=10000;i++) ans=max(ans,dp[i]);
printf("Case #%lld: %lld\n",r,ans);
}
return 0;
}
T3
\(AC\ \ on\ \ 2021.06.13\)
就大模拟,没啥好说的,代码调了一个下午。
注意反转数串,注意循环里要先 n++
(但是要是你循环里面先 +1 了循环前面就不要再 +1 了),注意每个数都只能走一遍,最重要的是注意读题(注意不能有 0 也不能有相同数字)……
橙题调这么久我还有救吗 qwq
\(Code\)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n;
bool check(ll i){
//把i转换为数串形式
int a[15]={},c[15]={};
int weishu=0;
while(i){
c[++weishu]=(int)i%(ll)10;
i/=(ll)10;
}
//反转!
for(int i=1;i<=weishu;i++) a[i]=c[weishu-i+1];
//无重复数字
for(int i=1;i<=weishu;i++)
for(int j=1;j<i;j++)
if(a[i]==a[j]) return false;
//去0判断
for(int i=1;i<=weishu;i++) if(!a[i]) return false;
//开始模拟
int x=1;
bool b[15]={};
for(int i=1;i<=weishu;i++){
int t=a[x];
while(t--){
x++;
if(x==weishu+1) x=1;
}
if(b[x]&&x!=1) return false;
b[x]=1;
if(x==1){
bool flag=1;
for(int i=1;i<=weishu;i++) flag&=b[i];
if(flag) return true;
else return false;
}
}
return false;
}
int main(){
scanf("%lld",&n);
while(1){
//printf("%d\n",n);
n++;
if(check(n)){
printf("%lld",n);
return 0;
}
}
return 0;
}
T4
\(AC\ \ on\ \ 2021.06.13\)
嗯,看来 mjl 是爱上大模拟了(逃。
没什么可说的了,我爱暴力((。
\(Code\)
#include<bits/stdc++.h>
using namespace std;
int n,x,y,a[20][20];
char zt='A';
int main(){
scanf("%d",&n);
for(int t=1;t<=n;t++){
scanf("%d %d",&x,&y);
if(t&1) zt='A',a[x][y]=1;
else zt='B',a[x][y]=2;
for(int i=1;i<=15;i++){
for(int j=1;j<=15;j++){
//横着的
if(i>=5){
if(a[i][j]==1&&a[i-1][j]==1&&a[i-2][j]==1&&a[i-3][j]==1&&a[i-4][j]==1){
printf("A %d",t);
return 0;
}
if(a[i][j]==2&&a[i-1][j]==2&&a[i-2][j]==2&&a[i-3][j]==2&&a[i-4][j]==2){
printf("B %d",t);
return 0;
}
}
if(i<=11){
if(a[i][j]==1&&a[i+1][j]==1&&a[i+2][j]==1&&a[i+3][j]==1&&a[i+4][j]==1){
printf("A %d",t);
return 0;
}
if(a[i][j]==2&&a[i+1][j]==2&&a[i+2][j]==2&&a[i+3][j]==2&&a[i+4][j]==2){
printf("B %d",t);
return 0;
}
}
//竖着的
if(j>=5){
if(a[i][j]==1&&a[i][j-1]==1&&a[i][j-2]==1&&a[i][j-3]==1&&a[i][j-4]==1){
printf("A %d",t);
return 0;
}
if(a[i][j]==2&&a[i][j-1]==2&&a[i][j-2]==2&&a[i][j-3]==2&&a[i][j-4]==2){
printf("B %d",t);
return 0;
}
}
if(j<=11){
if(a[i][j]==1&&a[i][j+1]==1&&a[i][j+2]==1&&a[i][j+3]==1&&a[i][j+4]==1){
printf("A %d",t);
return 0;
}
if(a[i][j]==2&&a[i][j+1]==2&&a[i][j+2]==2&&a[i][j+3]==2&&a[i][j+4]==2){
printf("B %d",t);
return 0;
}
}
//左上右下斜
if(i>=5&&j>=5){
if(a[i][j]==1&&a[i-1][j-1]==1&&a[i-2][j-2]==1&&a[i-3][j-3]==1&&a[i-4][j-4]==1){
printf("A %d",t);
return 0;
}
if(a[i][j]==2&&a[i-1][j-1]==2&&a[i-2][j-2]==2&&a[i-3][j-3]==2&&a[i-4][j-4]==2){
printf("B %d",t);
return 0;
}
}
if(i<=11&&j<=11){
if(a[i][j]==1&&a[i+1][j+1]==1&&a[i+2][j+2]==1&&a[i+3][j+3]==1&&a[i+4][j+4]==1){
printf("A %d",t);
return 0;
}
if(a[i][j]==2&&a[i+1][j+1]==2&&a[i+2][j+2]==2&&a[i+3][j+3]==2&&a[i+4][j+4]==2){
printf("B %d",t);
return 0;
}
}
//左下右上斜
if(j>=5&&i<=11){
if(a[i][j]==1&&a[i+1][j-1]==1&&a[i+2][j-2]==1&&a[i+3][j-3]==1&&a[i+4][j-4]==1){
printf("A %d",t);
return 0;
}
if(a[i][j]==2&&a[i+1][j-1]==2&&a[i+2][j-2]==2&&a[i+3][j-3]==2&&a[i+4][j-4]==2){
printf("B %d",t);
return 0;
}
}
if(i>=5&&j<=11){
if(a[i][j]==1&&a[i-1][j+1]==1&&a[i-2][j+2]==1&&a[i-3][j+3]==1&&a[i-4][j+4]==1){
printf("A %d",t);
return 0;
}
if(a[i][j]==2&&a[i-1][j+1]==2&&a[i-2][j+2]==2&&a[i-3][j+3]==2&&a[i-4][j+4]==2){
printf("B %d",t);
return 0;
}
}
}
}
}
printf("Tie");
return 0;
}
据说有个小五打了 5.6K,好可怕
T5
\(AC\ \ on\ \ 2021.06.14\)
广搜(数据范围很水),不过要注意,在算这个点能不能走到终点的时候,必须老老实实地从这个点出发走到终点,不能从终点倒回来枚举 (别问我怎么知道的)。
不会 T 掉,数据范围是真的水。
这里我打了两个差不多的 bfs 函数,只不过一个没有返回值一个是 bool
型的。其实这里可以用数组实现,一个 bfs 函数就够了,但是我懒得打,反正能 A。
\(Code\)
#include<bits/stdc++.h>
using namespace std;
char a[55][55];
int m,n,sx,sy,tx,ty;
bool b[55][55],c[55][55];
int dir[4][2]={{0,-1},{0,1},{-1,0},{1,0}};
struct node{int x,y;}t1,t2;
void bfs(int x,int y){
queue<node> q;
t1.x=x,t1.y=y;
q.push(t1);
while(!q.empty()){
t1=q.front();
q.pop();
int dx,dy;
int start,end; //循环开始与结束
if(a[t1.x][t1.y]=='.'&&a[t1.x+1][t1.y]=='#') continue;
if(a[t1.x][t1.y]=='+'||a[t1.x][t1.y]=='S'||a[t1.x][t1.y]=='T') start=0,end=4;
else if(a[t1.x][t1.y]=='-') start=0,end=2;
else if(a[t1.x][t1.y]=='|') start=2,end=4;
else if(a[t1.x][t1.y]=='.') start=3,end=4;
else continue;
for(int i=start;i<end;i++){
dx=t1.x+dir[i][0];
dy=t1.y+dir[i][1];
if(dx>=1&&dx<=m&&dy>=1&&dy<=n&&a[dx][dy]!='#'){
if(b[dx][dy]) continue;
b[dx][dy]=1;
t2.x=dx,t2.y=dy;
q.push(t2);
}
}
}
return;
}
//判断是否能到达终点
bool bfs2(int x,int y){
memset(c,0,sizeof(c));
queue<node> q;
t1.x=x,t1.y=y;
q.push(t1);
while(!q.empty()){
t1=q.front();
q.pop();
if(t1.x==tx&&t1.y==ty) return true;
int dx,dy;
int start,end;
if(a[t1.x][t1.y]=='.'&&a[t1.x+1][t1.y]=='#') continue;
if(a[t1.x][t1.y]=='+'||a[t1.x][t1.y]=='S'||a[t1.x][t1.y]=='T') start=0,end=4;
else if(a[t1.x][t1.y]=='-') start=0,end=2;
else if(a[t1.x][t1.y]=='|') start=2,end=4;
else if(a[t1.x][t1.y]=='.') start=3,end=4;
else continue;
for(int i=start;i<end;i++){
dx=t1.x+dir[i][0];
dy=t1.y+dir[i][1];
if(dx>=1&&dx<=m&&dy>=1&&dy<=n&&a[dx][dy]!='#'){
if(c[dx][dy]) continue;
c[dx][dy]=1;
t2.x=dx,t2.y=dy;
q.push(t2);
}
}
}
return false;
}
int main(){
scanf("%d %d",&m,&n);
for(int i=1;i<=m;i++){
scanf("\n");
for(int j=1;j<=n;j++){
scanf("%c",&a[i][j]);
if(a[i][j]=='S') sx=i,sy=j;
else if(a[i][j]=='T') tx=i,ty=j;
}
}
bfs(sx,sy);
if(!b[tx][ty]){
printf("I'm stuck!");
return 0;
}
int sum=0;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(!bfs2(i,j)&&b[i][j]) sum++;
}
}
printf("%d",sum);
return 0;
}
T6
\(AC\ \ on\ \ 2021.06.15\)(只可惜比赛已经结束了 qwq)
30 分一定是万恶的全排列了 qwq
不!我们不能思想只停留在部分分!
好吧这题是道 DP。
思路和大家的差不多,不讲!
话说我竟然不看 TJ 想到了这个思路就很那啥。
最关键的是我竟然没想到区间求和的优化就很那啥。
\(Code\)
#include<bits/stdc++.h>
using namespace std;
int n,m,sum,dp[1005][1005];
const int p=10000;
int main(){
scanf("%d %d",&n,&m);
dp[1][0]=1;
for(int i=2;i<=n;i++){
sum=0;
for(int j=0;j<=m;j++){
sum=(sum+dp[i-1][j])%p;
dp[i][j]=sum;
if(j+1>=i) sum=(sum-dp[i-1][j-i+1]+p)%p; //括号里要加上取余的数不然会取爆
}
}
printf("%d",dp[n][m]);
return 0;
}
T7
易证:mjl 爱上了大模拟之后一定又爱上了 HAOI……
紫题搞毛线啊。
溜了溜了。