前言
240分
100+80+20+40
T3少取了一个模结果全挂掉了(好不容易推出来了…)
T2也因为各种奇怪的错误挂了分
qwq
吸取教训吧
考场
今天先看题
T1第一眼看错了题意觉得水的不行
T3YBT原题且很水
T2T4乍看不太可做
因为错误审题,决定先写自以为很水的T1
写完样例不对,才发现自己审题完全审错了
那个翻折的关键性质又没有看出来(都看出来了吗,我感觉并不显然啊qwq)
分析了一会性质感觉打表或许可行
但可能是道搬砖题
此时大概8:40
于是转T3稳一稳
此时心态有些不稳了
(我甚至觉得T3的3e7会炸)
把T3超级暴力的《正解》floyd敲完还不太放心
但是也没有什么太好的方法
转回T1死磕
9:30
T1走上了慢慢打表之路
打了30min终于把恶心的转移数组敲完了
此时已经感觉药丸
但是编译结果有点惊喜
一遍过了样例???
又测了几个位置也对了
说实话那个搬砖代码一个bug没有真的挺神奇的
我本来已经做好了和它死磕的准备
结果就这么过了?
重新燃起希望
10:20
来到T2
很不错的时我很快发现了它的关键性质
利用一半为分界点递归转移
然后后面再跟个二分
check的地方递归求个数
很愉快的切掉了这道挺难的题
有一说一这道应该是我这几次模拟做的最好的一道题
确实有逻辑分析在里面
遗憾的是我切掉的时候也有点激动
手一抖最后的一步乘法没有取模
…
11:00
此时 我以为 我已经切了3题
心态就平和了起来
推了一会T4没有任何思路
就决定写个好一点的部分分下班
20分还是很好写的
40分也不太难
(又开始暴力搬砖 )
11:30
这次时间有些紧凑
T1和T3浪费了太多时间
我没有很多的时间检查了
(说不定再看看T2的沙雕错误就瞅出来了呢qwq)
最后就带着那个bug走出了考场
qwq
复盘
T1 road
正解简单的离谱
关键是回溯时对原图进行一个神奇的反转操作
就很easy了
但为了纪念还是附上打表代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+100;
int n;
int a,b;
int mi[32];
int shunpl[5][5]={{},{0,1,1,1,3},{0,4,2,2,2},{0,3,1,3,3},{0,4,4,2,4}};
int shundir[5][5]={{},{0,2,1,1,2},{0,2,2,1,1},{0,1,2,2,1},{0,1,1,2,2}};
int shunid[5][5]={{},{0,1,2,3,4},{0,4,1,2,3},{0,3,4,1,2},{0,2,3,4,1}};
int nipl[5][5]={{},{0,1,3,1,1},{0,2,2,4,2},{0,3,3,3,1},{0,2,4,4,4}};
int nidir[5][5]={{},{0,1,1,2,2},{0,2,1,1,2},{0,2,2,1,1},{0,1,2,2,1}};
int niid[5][5]={{},{0,1,4,3,2},{0,2,1,4,3},{0,3,2,1,4},{0,4,3,2,1}};
int dx[5]={0,0,0,1,1},dy[5]={0,0,1,1,0};
/*
1:shun
2:ni
*/
int x2,y2,x3,y3;
void find(int k,int pl,int dir,int id,int x,int y){
int ed=id+mi[2*k]-1;
if((a<id||a>ed)&&(b<id||b>ed)) return;
if(k==0){
if(id==a){
x2=x;y2=y;
}
if(id==b){
x3=x;y3=y;
}
return;
}
if(dir==1){//shun
int len=mi[k-1],tot=mi[(k-1)*2];
for(int i=1;i<=4;i++){
find(k-1,shunpl[pl][i],shundir[pl][i],id+(shunid[pl][i]-1)*tot,x+dx[i]*len,y+dy[i]*len);
}
return;
}
else{
int len=mi[k-1],tot=mi[(k-1)*2];
for(int i=1;i<=4;i++){
find(k-1,nipl[pl][i],nidir[pl][i],id+(niid[pl][i]-1)*tot,x+dx[i]*len,y+dy[i]*len);
}
return;
}
}
int main(){
// freopen("road.in","r",stdin);
// freopen("road.out","w",stdout);
int t;
scanf("%d",&t);
mi[0]=1;
for(int i=1;i<=30;i++) mi[i]=mi[i-1]<<1;
while(t--){
scanf("%d%d%d",&n,&a,&b);
find(n,1,1,1,1,1);
//printf("a=(%d,%d) b=(%d,%d)\n",x2,y2,x3,y3);
printf("%.0lf\n",10.0*sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2)));
}
return 0;
}
/*
3
1 1 2
2 16 1
3 4 33
*/
T2 shop
本题std的二分很神奇
类似于一个二分相对大小的最大值
然后硬限制一个范围
就过了…
觉得还是我的代码更好理解一写qwq(所有人对自己的代码都是这么想的)
不取模,见祖宗
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=105;
const int mod=1e9+7;
int n,k;
int solve(int x){
if(x==0) return 0;
return x+solve(x/2);
}
int find(int l,int r){
if(l>r) return 0;
if(r==0) return 0;
return r-l+1 + find((l+1)/2,r/2);
}
ll ksm(ll x,int k){
ll ans=1,res=x;
while(k){
if(k&1) ans=ans*res%mod;
res=res*res%mod;
k>>=1;
}
return ans;
}
void work(int k,int n){
int tot=solve(n/2);
if(k<=tot){
work(k,n/2);return;
}
k-=tot;
// printf("n=%d tot=%d k=%d\n",n,tot,k);
int o=k/n,p=k%n;
if(p==0){
printf("%lld\n",n*ksm(2,o-1)%mod);
return;
}
int st=n/2+1,ed=n;
while(st<ed){
int mid=st+ed>>1;
// printf(" l=%d r=%d find=%d\n",n/2+1,mid,find(n/2+1,mid));
if(find(n/2+1,mid)>=p) ed=mid;
else st=mid+1;
}
printf("%lld\n",st*ksm(2,o)%mod);
}
int main(){
// freopen("shop.in","r",stdin);
// freopen("shop.out","w",stdout);
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&k,&n);
work(k,n);
}
return 0;
}
/*
5
3 1
3 2
5 3
1000000000 1
987654321 876543210
1
32 10
*/
T3 run
YBT原题且很水
这也挂分就离谱
有一个是没有特判m=1的情况
还有一个是因为int的范围k只枚举到30而不是31!
头疼
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=105;
int n,m;
bool f[33][N][N];
int dis[N][N];
int main(){
// freopen("run.in","r",stdin);
// freopen("run.out","w",stdout);
int t;
scanf("%d",&t);
while(t--){
memset(f,0,sizeof(f));
memset(dis,0x3f,sizeof(dis));
// if(n==1){
// printf("0\n");
// continue;
// }
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
f[0][x][y]=1;
}
for(int k=1;k<=30;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
//if(i==j) continue;
for(int p=1;p<=n;p++){
//if(p==i||p==j) continue;
if(f[k-1][i][p]&&f[k-1][p][j]){
f[k][i][j]=1;
// printf(" p=%d\n",p);
break;
}
}
// printf("k=%d i=%d j=%d f=%d\n",k,i,j,f[k][i][j]);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
//if(i==j) continue;
for(int k=0;k<=30;k++){
if(f[k][i][j]){
// printf("ok:k=%d i=%d j=%d\n",k,i,j);
dis[i][j]=1;break;
}
}
}
dis[i][i]=0;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
printf("%d\n",dis[1][n]);
}
return 0;
}
/*
1
5 5
1 4
4 1
1 2
2 3
3 5
*/
T4 stairs
这题考场确实不太可做
考后写起来发现反而不难了
状压求出转移矩阵再快速幂加速即可
一个重要的技巧是把0规定为有挡板
这样不同高度之间可以无缝连接
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=105;
const int mod=1e9+7;
int n,k;
int w[8];
struct matrix{
int x,y;
ll a[130][130];
void clear(){
for(int i=0;i<=x;i++)
for(int j=0;j<=y;j++) a[i][j]=0;
}
};
int mi[8];
void print(matrix o){
for(int i=0;i<=min(3,o.x);i++){
for(int j=0;j<=3;j++) printf("%d ",o.a[i][j]);
printf("\n");
}
return;
}
matrix cheng(matrix a,matrix b){
matrix o;
//printf("Mul:\n") ;
//print(a);print(b);
o.x=a.x;o.y=b.y;o.clear();
for(int i=0;i<=o.x;i++){
for(int j=0;j<=o.y;j++){
for(int k=0;k<=a.y;k++){
o.a[i][j]=(o.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
//if(a.a[i][k]*b.a[k][j]) printf(" i=%d j=%d k=%d %d*%d a=%d\n",i,j,k,a.a[i][k],b.a[k][j],o.a[i][j]);
}
}
}
return o;
}
int dp[130][2];//dp[i][op]op:下面的边
matrix trans[8];
void init(){
mi[0]=1;
for(int i=1;i<=7;i++) mi[i]=mi[i-1]<<1;
for(int k=1;k<=7;k++){
trans[k].x=trans[k].y=mi[7]-1;
for(int i=0;i<mi[k];i++){
for(int j=0;j<mi[k];j++){
dp[0][1]=1;dp[0][0]=0;
for(int p=1;p<=k-1;p++){
if((i|j)&mi[p-1]){
dp[p][1]=dp[p-1][0]+dp[p-1][1];
dp[p][0]=dp[p-1][1]+dp[p-1][0];
}
else{
dp[p][1]=dp[p-1][0];
dp[p][0]=dp[p-1][1]+dp[p-1][0];
}
dp[p][0]%=mod;
dp[p][1]%=mod;
}
if((i|j)&mi[k-1]) trans[k].a[i][j]=dp[k-1][0]+dp[k-1][1];
else trans[k].a[i][j]=dp[k-1][0];
//printf("k=%d i=%d j=%d trans=%d\n",k,i,j,trans[k].a[i][j]);
}
}
}
}
matrix ans;
int main(){
for(int i=1;i<=7;i++) scanf("%d",&w[i]);
init();
ans.x=0;ans.y=mi[7]-1;
ans.a[0][0]=1;for(int i=1;i<=ans.y;i++) ans.a[0][i]=0;
for(int k=1;k<=7;k++){
//printf("k=%d trans:\n",k);
//print(trans[k]);
while(w[k]){
//printf("k=%d\n",w[k]);
if(w[k]&1){
ans=cheng(ans,trans[k]);
//printf("ans:\n");
//for(int i=0;i<=4;i++) printf("%d ",ans.a[0][i]);
//printf("\n");
}
trans[k]=cheng(trans[k],trans[k]);
//printf("trans:\n");
//print(trans[k]);
w[k]>>=1;
}
}
printf("%lld\n",ans.a[0][0]);
return 0;
}
/*
5
3 1
3 2
5 3
1000000000 1
987654321 876543210
1
32 10
*/
总结
争取吃一堑长一智吧
以后检查代码注意的东西又多了一个:取模是否彻底!
明天:字符串 加油!awa