D1:
T1:快速幂
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cstdlib> #include<cmath> #define LL long long using namespace std; LL n,m,k,x; inline LL quickpow(LL a,LL b){//a^b %nLL ans=1ll;while(b){if(b&1)ans=ans*a%n;a=a*a%n;b>>=1;}return ans; } int main(){ //freopen("circle.in","r",stdin); //freopen("circle.out","w",stdout);scanf("%lld%lld%lld%lld",&n,&m,&k,&x);printf("%lld",(x%n+m*quickpow(10ll,k)%n)%n);return 0; }
T2:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cstdlib> #include<cmath> #include<map> #define LL long long using namespace std; const int maxn=1e5+5; const int P=99999997; int n; int a[maxn],b[maxn],to[maxn],ans; map<int ,int >pa; map<int ,int >pb;int sum[maxn]; inline int lowbit(int x){return x&(-x);} inline int query(int p){int ans=0;while(p){ans+=sum[p];p-=lowbit(p);}return ans; } inline void modify(int p){while(p<=n){sum[p]++;p+=lowbit(p);} } int main(){//freopen("match.in","r",stdin);//freopen("match.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);pa[a[i]]=i;}for(int i=1;i<=n;i++){scanf("%d",&b[i]);pb[b[i]]=i;}sort(a+1,a+n+1);sort(b+1,b+n+1);/*
这里用到了排序不等式,(a-b)^2==a^2+b^2-2ab, 找到一个排列 s.t. -2ab max 自然想到排序不等式
正序和 <= 乱序和 <= 逆序和
*/for(int i=1;i<=n;i++){to[ pa[a[i]] ]=pb[b[i]];}memset(sum,0,sizeof(sum));ans=0;for(int i=n;i;i--){//由于是相邻的两个火柴交换,直接求逆序对ans=(ans+query(to[i]-1))%P;modify(to[i]);}printf("%d\n",ans);return 0; }
T3:
这题挺不好想,但是从部分分出发
30` && 60` 有向图两点间最小边最大,二分答案,O(q *log( m)* m )
但是其中填边的步骤可以省略,O(q*m)--------->kruscal 第一个使得两点联通的 边就是答案
100` 我们发现 每个询问都会填边太麻烦,然后我们想,推出两个性质
1:
如果该边是答案,那么他一定在该图的最大生成树中(反证法)
2:
如果该边是答案,那么两点联通 当且仅当 该边被添加(反证法)
于是就得到了满分算法,最大生成树+LCA最小边
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cstdlib> #include<cmath> #define LL long long using namespace std; const int maxn=1e4+5; const int maxm=5e4+5; struct Edge{int u;int v;int w;const bool operator<(const Edge &x)const{return w<x.w;}inline void read(){scanf("%d%d%d",&u,&v,&w);} }e[maxm]; int n,m,q;int father[maxn]; int find(int x){return father[x]==x ? x : father[x]=find(father[x]);}//dsuint fst[maxn],nxt[maxm<<1],to[maxm<<1],w[maxm<<1],edge_count; inline void add(int x,int y,int z){edge_count++;to[edge_count]=y;w[edge_count]=z;nxt[edge_count]=fst[x];fst[x]=edge_count; }inline void kruscal(){for(int i=1;i<=n;i++)father[i]=i;//dsu_init sort(e+1,e+m+1);for(int i=m;i;i--){//鏈€澶х敓鎴愭爲int fu=find(e[i].u);int fv=find(e[i].v);if(fu==fv)continue;father[fu]=fv;add(e[i].u,e[i].v,e[i].w);add(e[i].v,e[i].u,e[i].w); } } const int INF=0x3f3f3f3f;int f[maxn][50],g[maxn][50],deep[maxn],tre[maxn],temp; void dfs(int u,int fa){tre[u]=temp;deep[u]=deep[fa]+1;for(int i=1;i<30;i++){f[u][i]=f[ f[u][i-1] ][i-1];g[u][i]=min(g[ f[u][i-1] ][i-1],g[u][i-1]);}for(int i=fst[u];i;i=nxt[i]){int v=to[i];if(v==fa)continue;f[v][0]=u;g[v][0]=w[i];dfs(v,u);} } inline void LCA_init(){memset(g,0x3f,sizeof(g));for(int i=1;i<=n;i++)if(!deep[i]){temp++; dfs(i,0);} }inline int LCA(int x,int y){int ans=INF;if(deep[x]<deep[y])swap(x,y);for(int i=29;i>=0;i--){if(deep[f[x][i]]>=deep[y]){ans=min(ans,g[x][i]);x=f[x][i];} }if(x==y)return ans;for(int i=29;i>=0;i--){if(f[x][i]!=f[y][i]){ans=min(ans,min(g[x][i],g[y][i]));x=f[x][i];y=f[y][i]; }}ans=min(ans,min(g[x][0],g[y][0]));return ans; } int main(){ //freopen("truck.in","r",stdin); //freopen("truck.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){e[i].read();}kruscal();LCA_init();scanf("%d",&q); for(int i=1,x,y;i<=q;i++){scanf("%d%d",&x,&y);if(tre[x]!=tre[y])printf("-1\n");else printf("%d\n",LCA(x,y));}return 0; }
D2:
T1:
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<cstdlib> #include<algorithm> #define LL long long using namespace std; const int maxn=1e5+5; int n,h[maxn]; LL ans; int main(){// freopen("block.in","r",stdin);// freopen("block.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&h[i]);ans=0ll;for(int i=1;i<=n+1;i++){if(h[i]<h[i-1]){ans+=1ll*(h[i-1]-h[i]);}}printf("%lld\n",ans);return 0; }
T2:
O(nlogn)???
虽然不是正解但是写的很开心,O(n^2)Dp+segment tree 优化
每次x要找比x大的 将要下降的 Dp值的最大值 +1
同理
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<cstdlib> #include<algorithm> using namespace std; const int maxn=1e5+5; const int maxh=1e6+5; /* main thought: segment tree,维护两个,存储一下 以num结尾的将要上升的所有Dp值 以num结尾的将要下降的所有Dp值每次x 从第一棵树里面找所有比他 小 的值中最大的Dp值 插入第二棵数中 从第二棵树里面找所有比他 大 的值中最大的Dp值 插入第一棵树中*/ struct Node{int l;int r;int len;Node(int L=0,int R=0,int Len=0):l(L),r(R),len(Len){} inline void update(const Node&a,const Node&b){len=max(a.len,b.len);}inline void modify(int x){len=max(len,x);} }L[maxh<<2][2]; //0->将要上升,1->将要下降 void build(int k,int l,int r,bool b){L[k][b]=Node(l,r,0);if(l==r)return;else{int mid=(l+r)>>1;build(k<<1,l,mid,b);build(k<<1|1,mid+1,r,b); return;} } void modify(int k,int p,int x,bool b){if(L[k][b].l==L[k][b].r) return L[k][b].modify(x);else{int mid=(L[k][b].l+L[k][b].r)>>1;if(p<=mid)modify(k<<1,p,x,b);else modify(k<<1|1,p,x,b);return L[k][b].update(L[k<<1][b],L[k<<1|1][b]);} } int query(int k,int l,int r,bool b){//max queryif(l<=L[k][b].l&&L[k][b].r<=r)return L[k][b].len;else{int mid=(L[k][b].l+L[k][b].r)>>1;int ans=0;if(l<=mid)ans=max(ans,query(k<<1,l,r,b));if(mid<r)ans=max(ans,query(k<<1|1,l,r,b));return ans;} } int n,h[maxn]; //0->将要上升,1->将要下降 int main(){//freopen("flower.in","r",stdin);//freopen("flower.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&h[i]);build(1,0,1000000,1);build(1,0,1000000,0);for(int i=1;i<=n;i++){if(h[i]<1000000)modify(1,h[i],query(1,h[i]+1,1000000,1)+1,0);//将要下降的max +1 加到 将要上升 中if(h[i]>0)modify(1,h[i],query(1,0,h[i]-1,0)+1,1);//将要上升的max +1 加到 将要下降 中 }
printf("%d\n",max( query(1,0,1000000,1) , query(1,0,1000000,0) ) );return 0; }
注意:!!!线段树进行修改查询的时候,要注意边界!!!
神奇做法:O(n)!!!
据说是找到拐点然后+2
std:
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> using namespace std; const int maxn = 1000000 + 10 ; int vis,ans,n,h[maxn]; int main() {//freopen("flower.in","r",stdin); //freopen("flower.out","w",stdout);cin>>n;for(int i=1;i<=n;i++) scanf("%d",&h[i]);if(h[2]>=h[1]) vis=1;for(int i=2;i<=n;i++){if(i==n && !vis) {ans++;break;}if(vis) if(h[i]>h[i+1]) {ans++;vis=0;continue;}if(!vis) if(h[i]<h[i+1]){ans++;vis=1;continue;}}cout<<ans+1<<endl;return 0; }
T3:
个人感觉写了双向广搜,理论上能将复杂度降低到 开一个根号
但是 忘记了 无解的情况都会跑满,所以比 单项广搜还慢一会
60`:
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<cstdlib> #include<algorithm> using namespace std; /* thought: 广搜判最短时间: 时间上:空间上:每种状态只和空白块位置和目标快位置有关 共30^4种状态。。。but 30^4*500=5e8双向广搜!!! 也行,但是终止状态是4种,目标块在目标位置,空白块在4周 */int n,m,Q; bool stable[50][50]; struct Node{int x,y;Node(int X=0,int Y=0):x(X),y(Y){}const bool operator==(const Node&a)const{return x==a.x&&y==a.y;}inline bool limit(){//判断是否合法return 0<x && x<=n && 0<y && y<=m && stable[x][y];}inline void read(){scanf("%d%d",&x,&y);}inline void write(){printf("%d %d\n",x,y);} }e,s,t; //0->正向,1->反向 struct Queue{//每种状态 Node S,W;Queue(Node SS=Node(0,0),Node WW=Node(0,0)):S(SS),W(WW){}inline void write(){printf("~~~~~~~~~\n");S.write();W.write();printf("~~~~~~\n");} }q[32*32*32*32][2]; int vis[32][32][32][32][2];//时间戳 判是否到达过 int step[32][32][32][32][2];//每种状态的步骤数 int front[2],rear[2];const int dx[4]={0,1,0,-1}; const int dy[4]={1,0,-1,0}; inline void bfs(int i){ //printf("------------%d\n",i);front[0]=front[1]=rear[0]=rear[1]=0;q[rear[0]++][0]=Queue(s,e);step[s.x][s.y][e.x][e.y][0]=0;vis[s.x][s.y][e.x][e.y][0]=i;//q[front[0]][0].write();for(int j=0;j<4;j++){Node a=Node(t.x+dx[j],t.y+dy[j]);//printf("\na::");a.write();if(a.limit()){q[rear[1]++][1]=Queue(t,a);step[t.x][t.y][a.x][a.y][1]=0;vis[t.x][t.y][a.x][a.y][1]=i;}}//printf("???%d %d ???",front[1],rear[1]);//for(int j=front[1];j<rear[1];j++)q[j][1].write();//printf("begin to search:::");while(front[0]<rear[0] && front[1]<rear[1]){if(rear[0]-front[0]<rear[1]-front[1]){Queue &bg=q[front[0]][0]; //printf("bg:");bg.write();if(vis[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][1]==i){printf("%d\n",step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][0]+step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][1]);return;}for(int j=0;j<4;j++){Node a=Node(bg.W.x+dx[j],bg.W.y+dy[j]);if(a.limit()){//a.write();if(a==bg.S){q[rear[0]][0]=Queue(bg.W,bg.S);}else{q[rear[0]][0]=Queue(bg.S,a);}Queue &ed=q[rear[0]][0];if(vis[ed.S.x][ed.S.y][ed.W.x][ed.W.y][0]!=i){step[ed.S.x][ed.S.y][ed.W.x][ed.W.y][0]=step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][0]+1;vis[ed.S.x][ed.S.y][ed.W.x][ed.W.y][0]=i;rear[0]++;}} }front[0]++; }else{Queue &bg=q[front[1]][1]; //printf("bg:");bg.write();if(vis[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][0]==i){printf("%d\n",step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][0]+step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][1]);return;} for(int j=0;j<4;j++){Node a=Node(bg.W.x+dx[j],bg.W.y+dy[j]);if(a.limit()){//a.write();if(a==bg.S){q[rear[1]][1]=Queue(bg.W,bg.S);}else{q[rear[1]][1]=Queue(bg.S,a);}Queue &ed=q[rear[1]][1];if(vis[ed.S.x][ed.S.y][ed.W.x][ed.W.y][1]!=i){step[ed.S.x][ed.S.y][ed.W.x][ed.W.y][1]=step[ bg.S.x ][ bg.S.y ][ bg.W.x ][ bg.W.y ][1]+1;vis[ed.S.x][ed.S.y][ed.W.x][ed.W.y][1]=i;rear[1]++;}} }front[1]++;}}printf("-1\n"); } int main(){freopen("puzzle.in","r",stdin);freopen("puzzle.out","w",stdout);scanf("%d%d%d",&n,&m,&Q);//printf("%d %d %d\n",n,m,Q);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int _x;scanf("%d",&_x);stable[i][j]=_x;}for(int i=1;i<=Q;i++){e.read();//e.write();s.read();//s.write();t.read();//t.write(); bfs(i);//if(i<q)memset(vis,0,sizeof(vis)); }return 0; }
70`:
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int maxm = 30 + 5; bool vis[maxm][maxm][maxm][maxm]; int map[maxm][maxm],n,m,q; int exe,eye,sxs,sys,txt,tyt; int dx[5]={0,0,0,1,-1},dy[5]={0,1,-1,0,0}; struct Node{int ex,ey,sx,sy,d;}; int bfs() {queue<Node> pq;pq.push((Node){exe,eye,sxs,sys,0});vis[exe][eye][sxs][sys]=1;while(!pq.empty()){int ex=pq.front().ex,ey=pq.front().ey,sx=pq.front().sx,sy=pq.front().sy,d=pq.front().d;pq.pop();for(int i=1;i<=4;i++){int nx=ex+dx[i],ny=ey+dy[i];if(nx<1 || nx>n || ny<1 || ny>m || !map[nx][ny]) continue; if(nx==sx && ny==sy){if(vis[nx][ny][ex][ey]) continue;if(ex==txt && ey==tyt) return d+1;else{pq.push((Node){nx,ny,ex,ey,d+1});vis[nx][ny][ex][ey]=1;}}else{if(vis[nx][ny][sx][sy]) continue;pq.push((Node){nx,ny,sx,sy,d+1});vis[nx][ny][sx][sy]=1;}}}return -1; } int main() {freopen("puzzle.in","r",stdin);freopen("puzzle.out","w",stdout);cin>>n>>m>>q;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&map[i][j]);for(int i=1;i<=q;i++){memset(vis,0,sizeof(vis));scanf("%d%d%d%d%d%d",&exe,&eye,&sxs,&sys,&txt,&tyt);cout<<(sxs==txt&&sys==tyt?0:bfs())<<endl;}return 0; }
std:懂了,就是写的非常曲折,总共改了10多次。。。
(ps:好题,值得一做)


1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<cstdlib> 6 #include<algorithm> 7 using namespace std; 8 /* 9 thought: 10 暴力预处理+ 对没种状态建图+spfa 11 */ 12 const int INF=0x3f3f3f3f; 13 14 int n,m,Q; 15 bool stable[50][50]; 16 struct Node{ 17 int x,y; 18 Node(int X=0,int Y=0):x(X),y(Y){} 19 20 const bool operator==(const Node&a)const{ 21 return x==a.x&&y==a.y; 22 } 23 inline bool limit(){//判断是否合法 24 return 0<x && x<=n && 0<y && y<=m && stable[x][y]; 25 } 26 inline void read(){scanf("%d%d",&x,&y);} 27 inline void write(){printf("%d %d\n",x,y);} 28 }e,s,t; 29 const int dx[4]={0,1,0,-1}; 30 const int dy[4]={1,0,-1,0};//下,右,上,左 31 32 int fst[40000],nxt[1000000],to[1000000],w[1000000],edge_count=0; 33 inline void add(int x,int y,int z){ 34 edge_count++; 35 to[edge_count]=y; 36 w[edge_count]=z; 37 nxt[edge_count]=fst[x]; 38 fst[x]=edge_count; 39 } 40 inline int get_hash(int x,int y,int k){ 41 return y*1000+x*10+k; 42 }//状态转数字 43 inline Node get_Node(int a){ 44 int xx,yy; 45 a/=10; 46 xx=a%100; 47 a/=100; 48 yy=a; 49 return Node(xx,yy); 50 } 51 bool vis[32][32]; 52 int step[32][32]; 53 Node q[32*32]; 54 inline int bfs(Node S,Node T){ 55 if(!S.limit() || !T.limit())return INF; 56 57 memset(vis,0,sizeof(vis)); 58 59 int front,rear; 60 front=rear=0; 61 62 q[rear++]=S; 63 vis[S.x][S.y]=1; 64 step[S.x][S.y]=0; 65 while(front<rear){ 66 Node &bg=q[front]; 67 if(bg==T)return step[bg.x][bg.y]; 68 69 for(int j=0;j<4;j++){ 70 Node a=Node(bg.x+dx[j],bg.y+dy[j]); 71 if(a.limit() && !vis[a.x][a.y]){ 72 73 /*if(S==Node(3,1)&&T==Node(1,1)){ 74 printf("%d",stable[a.x][a.y]); 75 //a.write(); 76 }*/ 77 78 step[a.x][a.y]=step[bg.x][bg.y]+1; 79 vis[a.x][a.y]=1; 80 q[rear++]=a; 81 } 82 } 83 front++; 84 } 85 return INF; 86 } 87 88 inline void Spfa_init(){ 89 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){ 90 if(stable[i][j]){ 91 stable[i][j]=0; 92 93 for(int k=0;k<4;k++) 94 { 95 Node a=Node(i+dx[k],j+dy[k]); 96 if(a.limit())add(get_hash(i,j,k),get_hash(a.x,a.y,(k+2)%4),1); 97 98 for(int l=k+1;l<4;l++){ 99 Node S=Node(i+dx[k],j+dy[k]); 100 Node T=Node(i+dx[l],j+dy[l]); 101 if(!S.limit() || !T.limit())continue; 102 103 int t=bfs(S,T); 104 //if(S==Node(3,1)&&T==Node(1,1))cout<<i<<j<<endl; 105 if(t!=INF) 106 //建图:(x,y,z)表示目标格子在(x,y)空白格子在z方向,向4个方向建边 107 { 108 add(get_hash(i,j,k),get_hash(T.x,T.y,(l+2)%4),t+1); 109 add(get_hash(i,j,l),get_hash(S.x,S.y,(k+2)%4),t+1); 110 } 111 112 113 } 114 } 115 116 stable[i][j]=1; 117 } 118 } 119 } 120 121 inline int bfs_sec(Node &E,Node S){ 122 memset(vis,0,sizeof(vis)); 123 124 int front,rear; 125 front=rear=0; 126 127 q[rear++]=E; 128 vis[E.x][E.y]=1; 129 step[E.x][E.y]=0; 130 131 while(front<rear){ 132 Node &bg=q[front]; 133 134 for(int j=0;j<4;j++){ 135 Node a=Node(bg.x+dx[j],bg.y+dy[j]); 136 137 if(a==S){ 138 E=bg; 139 //E.write(); 140 141 return step[bg.x][bg.y]; 142 } 143 144 if(a.limit() && !vis[a.x][a.y]){ 145 step[a.x][a.y]=step[bg.x][bg.y]+1; 146 vis[a.x][a.y]=1; 147 q[rear++]=a; 148 } 149 } 150 front++; 151 } 152 return INF; 153 } 154 int que[400000],dis[400000]; 155 bool inqueue[40000]; 156 inline int spfa(int ss,Node T){ 157 /*知道自己错在哪里了: 158 我的想法是 一开始让空白块跑到目标块旁边 159 但是这种方法会有漏洞,就是这次的路径可能以后的最优解会路过 160 161 也就是起点不在图里,需要从起点的上下左右跑一边再计算最短路 162 */ 163 memset(dis,0x3f,sizeof(dis)); 164 int ans=INF; 165 166 int front,rear; 167 front=rear=0; 168 169 que[rear++]=ss; 170 dis[ss]=0; 171 inqueue[ss]=1; 172 173 while(front<rear){ 174 int &bg=que[front]; 175 //printf("%d:\n",bg); 176 if(get_Node(que[front])==T)ans=min(ans,dis[bg]); 177 178 for(int i=fst[bg];i;i=nxt[i]){ 179 int v=to[i]; 180 //printf(" v%d ",v); 181 int tt=dis[bg]+w[i]; 182 //printf("dis%d\n",tt); 183 184 if(tt<dis[v]){ 185 dis[v]=tt; 186 if(!inqueue[v]){ 187 que[rear++]=v; 188 inqueue[v]=1; 189 } 190 } 191 192 } 193 194 inqueue[bg]=0; 195 front++; 196 } 197 return ans; 198 } 199 inline void solve(){ 200 if(s==t){ 201 printf("0\n"); 202 return; 203 } 204 stable[s.x][s.y]=0; 205 206 int ans=INF; 207 for(int i=0;i<4;i++){ 208 int a=spfa(get_hash(s.x,s.y,i),t); 209 if(a==INF)continue; 210 211 int b=bfs(Node(s.x+dx[i],s.y+dy[i]),e); 212 if(b==INF)continue; 213 214 ans=min(ans,a+b); 215 } 216 stable[s.x][s.y]=1; 217 218 if(ans==INF)printf("-1\n"); 219 else printf("%d\n",ans); 220 } 221 int main(){ 222 //freopen("puzzle.in","r",stdin); 223 //freopen("puzzle.out","w",stdout); 224 scanf("%d%d%d",&n,&m,&Q); 225 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){ 226 int _x;scanf("%d",&_x);stable[i][j]=_x; 227 } 228 Spfa_init(); 229 230 for(int i=1;i<=Q;i++){ 231 e.read();//e.write(); 232 s.read();//s.write(); 233 t.read();//t.write(); 234 solve(); 235 //if(i<q)memset(vis,0,sizeof(vis)); 236 } 237 return 0; 238 } 239 /* 240 3 3 1 241 1 1 1 242 1 0 1 243 1 1 1 244 3 1 1 1 1 2 245 */