题目链接:点击打开链接
说明:前五题简单题就不写了。。。
F:这是裸nlogn的求最长上升序列算法,前后各求一下取小就行了。
#include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<queue> using namespace std; typedef long long ll; const int mx = 5e5+10,mod = 1e9+7; int n,m; int fron[mx],back[mx],a[mx],b[mx]; int main(){ fron[0]=0; while(~scanf("%d",&n)){ for(int i=0;i<n;i++) scanf("%d",a+i); int len=1; b[0] = a[0]; for(int i=1;i<n;i++){ int k = lower_bound(b,b+len,a[i])-b; if(k==len) len++; b[k]=a[i], fron[i]=k; } len = 1, back[n-1] = 0; b[0] = a[n-1]; for(int i=n-2;i>=0;i--){ int k = lower_bound(b,b+len,a[i])-b; if(k==len) len++; b[k]=a[i], back[i]=k; } int ans = 0; for(int i=0;i<n;i++) ans = max(ans,min(fron[i],back[i])*2+1); printf("%d\n",ans); } return 0; }G:贪心思路。按攻击力从大到下排序,相同的按血量从小到大排序。然后比较。 #include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<queue> #include<set> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int mx = 20; int n,m; struct data{ int v,a; data(){} data(int vv,int aa){ v = vv, a = aa ; } bool operator < (data A)const{ if(a==A.a) return v<A.v; return a>A.a; } }s[mx],q[mx]; int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d%d",&s[i].v,&s[i].a); for(int i=0;i<n;i++) scanf("%d%d",&q[i].v,&q[i].a); sort(q,q+n); int j = 0, k = 0; while(j<n&&k<n){ int vj = (q[k].v-1)/s[j].a+1, vk = (s[j].v-1)/q[k].a+1; if( vj < vk ) s[j].v -= vj*q[k].a, k++; else if( vj > vk ) q[k].v -= vk*s[j].a, j++; else j++ ,k++; } puts(k==n? "NO":"YES"); } return 0; }H:考虑到n才2w,直接用vector全部存入容器中,直接暴力。 #include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<queue> #include<set> #include<vector> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int mx = 2e4+10; int n,m,a[mx]; vector <int> st[mx/2]; int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d",a+i); for(int i=0;i<=n/2;i++) st[i].clear(); for(int i=1;i<=n/2;i++){ int j = 0; while(j*i<n){ st[i].push_back(a[j*i]); j++; } sort(st[i].begin(),st[i].end()); } while(m--){ int x,y; scanf("%d%d",&x,&y); if(x>n/2&&x<n){ if(y==1) printf("%d\n",max(a[x],a[0])); else if(y==2) printf("%d\n",min(a[x],a[0])); else puts("-1"); } else if(x>=n) printf("%d\n",y==1? a[0]:-1); else printf("%d\n",y>st[x].size()? -1:st[x][st[x].size()-y]); } }I:动态规划面积从小到大,已知n<=2&&m<=2的棋盘必为必败态,然后规划每个点是否能进入至少一个必败态,则其就是必胜态,反之必败。
#include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<queue> #include<set> #include<vector> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int mx = 5e2+100; int n,m,pri[mx],top; bool vis[mx],vic[mx][mx]; void init(){ for(int i=2;i<mx;i++){ if(!vis[i]) pri[top++] = i; for(int j=0;j<top&&pri[j]*i<mx;j++){ vis[pri[j]*i] = 1; if(i%pri[j]==0) break; } } } int main(){ int t,top = 0; init(); memset(vic,0,sizeof(vic)); for(int i=1;i<=500;i++){ for(int j=1;j<=500;j++){ if(i<=2&&j<=2) continue; int k = 0; while(!vic[i][j]&&pri[k]<i){ if(!vic[i-pri[k]][j]) vic[i][j] = 1; k++; } k = 0; while(!vic[i][j]&&pri[k]<j){ if(!vic[i][j-pri[k]]) vic[i][j] = 1; k++; } k = 0; while(!vic[i][j]&&pri[k]<j&&pri[k]<i){ if(!vic[i-pri[k]][j-pri[k]]) vic[i][j] = 1; k++; } } } scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); puts(vic[n][m]? "Sora":"Shiro"); } return 0; }J:代码丢了(不想写了。。。)简单说你会发现要是没有233的限制,那么每个n累加的值应该是(n*n+n)/2,那么用这个值减去i的1-232和后面的n-232到n就是答案了。这两个分别用到O(n)的求1-n的欧拉函数和O(sqrt(n))的求1-n的欧拉函数。K:二分求答案
#include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<queue> #include<set> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int mx = 1e5+10; int n,m; struct data{ int ai,bi; }s[mx]; bool cmp_1(data A,data B){ if(A.bi==B.bi) return A.ai>B.ai; return A.bi<B.bi; } bool check(int x,int si){ int sum = 0, cnt = 0; for(int i=0;i<n;i++){ if(s[i].ai>=x){ cnt++; sum += s[i].bi; } if(cnt==si) break; } return cnt==si&&sum<=m; } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d%d",&s[i].ai,&s[i].bi); sort(s,s+n,cmp_1); int top = 0,sum = m; while(top<n&&sum>=s[top].bi){ sum -= s[top].bi; top++; } int l = 1,r = 1e4; while(l<=r){ int mid = (l+r)>>1; if(check(mid,top)) l = mid+1; else r = mid-1; } printf("%d %d\n",top,r); } return 0; } M:线段树维护一个点增加最多的值和减少最多的值。当然用到了懒人思想。 #include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<queue> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int mx = 1e5+10,mod = 1e9+7; int n,m,num[mx<<2],q,a[mx]; int just[mx<<2],nage[mx<<2]; struct data{ int MAX,MIN; data(){} data(int maxx,int minn){ MIN = minn, MAX = maxx ; } }; void Splite(int rt){ just[rt<<1] = max(just[rt<<1],num[rt<<1]+just[rt]); just[rt<<1|1] = max(just[rt<<1|1],num[rt<<1|1]+just[rt]);; nage[rt<<1] = min(nage[rt<<1],num[rt<<1]+nage[rt]); nage[rt<<1|1] = min(nage[rt<<1|1],num[rt<<1|1]+nage[rt]); num[rt<<1] += num[rt]; num[rt<<1|1] += num[rt]; just[rt] = nage[rt] = num[rt] = 0; } void update(int L,int R,int l,int r,int rt,int v){ if(L<=l&&R>=r){ num[rt]+=v; just[rt] = max(just[rt],num[rt]); nage[rt] = min(nage[rt],num[rt]); return ; } if(num[rt]||just[rt]||nage[rt]) Splite(rt); int mid = (l+r)>>1; if(L<=mid) update(L,R,lson,v); if(R>mid) update(L,R,rson,v); } data query(int L,int l,int r,int rt){ if(l==r) return data(just[rt],nage[rt]); if(just[rt]||nage[rt]||num[rt]) Splite(rt); int mid = (l+r)>>1; if(L<=mid) return query(L,lson); return query(L,rson); } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%d",a+i); memset(num,0,sizeof(num)); memset(just,0,sizeof(just)); memset(nage,0,sizeof(nage)); while(q--){ int d; scanf("%d",&d); if(d==1){ int x,y,z; scanf("%d%d%d",&x,&y,&z); update(x,y,1,n,1,z); }else{ scanf("%d",&d); data t = query(d,1,n,1); printf("%d\n",max(abs(a[d]+t.MAX),abs(a[d]+t.MIN))); } } } return 0; }O: 题目告诉我们当然主人公够聪明,但是不知道传送门是怎么对应的,那么此时可以看做只有两个操作。一:不进入传送门直接走。二:进入离出发点最近的传送门(毕竟不知道肯定是选择最近的啊)。然后用一个bfs套dfs将传送门出口作为新的出发点,看看是否能到达终点,若有一种不能则为-1.#include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<queue> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int mx = 1e2+10,co[4][2]={1,0,0,1,-1,0,0,-1}; int n,m,cnt1,ans; char map[mx][mx]; struct node{ int x,y,k; node(){} node(int xx,int yy,int kk){ x = xx, y = yy, k = kk; } }a[5],b[5]; bool vis2[5]; int bfs(int beg,int eng){ queue<node> skt; bool vis[mx][mx],flag = 0; int sum = inf; memset(vis,0,sizeof(vis)); skt.push(node(beg,eng,0)); vis[beg][eng]=1; while(!skt.empty()){ node no = skt.front(); skt.pop(); for(int i=0;i<4;i++){ node po = node(no.x+co[i][0],no.y+co[i][1],no.k+1); if(po.x<0||po.y<0||po.x>=n||po.y>=m) continue; if(vis[po.x][po.y]||map[po.x][po.y]=='#') continue; vis[po.x][po.y] = 1; if(map[po.x][po.y]=='T') return min(sum,po.k); if(!flag&&map[po.x][po.y]=='i'){ map[po.x][po.y] = '.'; for(int j=0;j<cnt1;j++){ if(vis2[j]) continue; vis2[j] = 1; if(sum==inf) sum = bfs(b[j].x,b[j].y)+po.k+1; else sum = max(sum,bfs(b[j].x,b[j].y)+po.k+1); vis2[j] = 0; } map[po.x][po.y] = 'i'; flag = 1; } skt.push(po); } } return sum; } int main(){ int t,beg,eng; scanf("%d",&t); while(t--){ ans = 0, cnt1 = 0; scanf("%d%d",&n,&m); for(int i=0;i<n;i++){ scanf("%s",map[i]); for(int j=0;j<m;j++){ if(map[i][j]=='S') beg = i, eng = j; else if(map[i][j]=='o') b[cnt1++]=node(i,j,0); } } ans = bfs(beg,eng); printf("%d\n",ans>=inf? -1:ans); } return 0; }