七个题七个贪心,题目是真的不行,但是既然写完了还是写一发solution
A
随便写
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<vector> #include<math.h> #include<queue> #include<set> #include<map> using namespace std; typedef long long ll; typedef long double db; typedef pair<int,int> pii; const int N=10000; const db pi=acos(-1.0); #define lowbit(x) (x)&(-x) #define sqr(x) (x)*(x) #define rep(i,a,b) for (register int i=a;i<=b;i++) #define per(i,b) for (register int i=a;i>=b;i--) #define fir first #define sec second #define mp(a,b) make_pair(a,b) #define pb(a) push_back(a) #define maxd 998244353 #define eps 1e-8 int read() { int x=0,f=1;char ch=getchar(); while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();} while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();} return x*f; } int main() { int T=read(); while (T--) { int a=read(),b=read(),c=read(),d=read(),k=read(),ok=0; rep(i,k) { int j=k-i; if ((i*c>=a) && (j*d>=b)) { cout << i << " " << j << endl; ok=1;break; } } if (!ok) cout << -1 << endl; } return 0; }
B
大力分类讨论
如果没有梯子,那么\(ans=n\)
如果有梯子,那么找到最左边的梯子\(l\)与最右边的梯子\(r\),则\(ans=max(n+1,(n-l+1)*2,r*2)\)。因为走了梯子的话不可能沿着继续的方向,否则答案恒为\(n+1\)
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<vector> #include<math.h> #include<queue> #include<set> #include<map> using namespace std; typedef long long ll; typedef long double db; typedef pair<int,b) #define pb(a) push_back(a) #define maxd 998244353 #define eps 1e-8 int n; char s[2020]; int read() { int x=0,f=1;char ch=getchar(); while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();} while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();} return x*f; } int main() { int T=read(); while (T--) { n=read(); scanf("%s",s+1); int ans=0; rep(i,1,n) if (s[i]=='1') {ans=n+1;} if (!ans) {printf("%d\n",n);continue;} int l=maxd,r=0; rep(i,n) if (s[i]=='1') { l=min(l,i); r=max(r,i); } ans=max(ans,max((n-l+1)*2,r*2)); cout << ans << endl; } return 0; }
C
你以为我是扩欧?其实我是暴力哒!
我们需要找到一组\(x,y\)满足\(x,y\geq 0\)且\(x+y\)最小,注意到\(d<w\leq 10^5\),根据同余那套理论不难知道如果有解,在\([0,w-1]\)中必然存在一个\(y\)的合法解,且此时\(y\)最小。不难发现这个时候也一定有\(x+y\)最小(因为对下一个合法的\(x,y\),根据系数关系知\(y\)的增大必然比\(x\)的减小大)。于是大力枚举就好了
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<vector> #include<math.h> #include<queue> #include<set> #include<map> using namespace std; typedef long long ll; typedef long double db; typedef pair<int,b) #define pb(a) push_back(a) #define maxd 998244353 #define eps 1e-8 #define int long long ll n,p,w,d; int read() { int x=0,f=1;char ch=getchar(); while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();} while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();} return x*f; } signed main() { n=read();p=read();w=read();d=read(); ll x=0,y=0;int ok=0; rep(i,w-1) { if (p<i*d) break; if ((p-i*d)%w==0) {y=i;ok=1;break;} } if (!ok) {puts("-1");return 0;} x=(p-y*d)/w; if (x+y>n) {puts("-1");return 0;} ll z=n-x-y; cout << x << " " << y << " " << z << endl; return 0; }
D
由抽屉原理知,合法图中不会存在度数\(>2\)的点,即一定是一条链。暴力枚举颜色排列即可
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<vector> #include<math.h> #include<queue> #include<set> #include<map> using namespace std; typedef long long ll; typedef long double db; typedef pair<int,b) #define pb(a) push_back(a) #define maxd 998244353 #define eps 1e-8 struct node{int to,nxt;}sq[200200]; int n,m,c[101001][4],id[4],col[100100],ansid[4],ans[4],p[100100],tot=0,all=0,head[100100]; int d[100100]; int read() { int x=0,f=1;char ch=getchar(); while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();} while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();} return x*f; } void add(int u,int v) { all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all;d[v]++; } void dfs(int u,int fu) { p[++tot]=u; for (int i=head[u];i;i=sq[i].nxt) { int v=sq[i].to; if (v==fu) continue; dfs(v,u); } } int main() { n=read(); rep(j,3) rep(i,n) c[i][j]=read(); rep(i,n-1) { int u=read(),v=read(); add(u,v);add(v,u); } int st=0,ed=0; rep(i,n) if (d[i]>2) { puts("-1");return 0; } else if (d[i]==1) { if (!st) st=i;else ed=i; } dfs(st,0); rep(i,3) id[i]=i; ll ans=1e18; //rep(i,n) cout << p[i] << " ";cout << endl; while (1) { ll now=0; rep(i,n) now+=c[p[i]][id[i%3+1]]; if (now<ans) { ans=now; rep(i,3) ansid[i]=id[i]; } if (!next_permutation(id+1,id+1+3)) break; } cout << ans << endl; rep(i,n) col[p[i]]=ansid[i%3+1]; rep(i,n) cout << col[i] << " "; return 0; }
E
辣鸡玩意毁我青春
考虑对于一个序列如何操作来减小目标值:必然是增大所有的最小值或者减小所有的最大值。同时又由于对两者操作是等效的,于是便可以贪心的选取位置较少的进行操作。
根据上面我们可以得到一个更一般的做法:我们枚举当前最小值的位置个数和有最大值的位置个数,由上面提到的做法不难知道这个数值必然会相等。如果当前这个局面是可以达成的,那就继续下去;否则我们使用剩下的操作次数提升全部的最小值(当然最大值也可以)
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<vector> #include<math.h> #include<queue> #include<set> #include<map> using namespace std; typedef long long ll; typedef long double db; typedef pair<int,b) #define pb(a) push_back(a) #define maxd 998244353 #define eps 1e-8 int n,a[100100]; ll k; int read() { int x=0,f=1;char ch=getchar(); while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();} while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();} return x*f; } int main() { n=read();scanf("%lld",&k); rep(i,n) a[i]=read(); sort(a+1,a+1+n); int l=1,r=n,ans=0; rep(i,n>>1) { ll now=1ll*(a[l+1]-a[l])*l+1ll*(a[r]-a[r-1])*(n-r+1); if (k<now) { ans=a[r]-a[l]-k/l; break; } k-=now;l++;r--; } printf("%d",ans); return 0; }
F
手玩一下可以得到一堆结论,这里给出我的做法中使用的性质
一段的\(B\)或\(W\)中,所有的位置都不会被更改
如果一个位置在某一次不会被更改,那么它接下来也不会被更改(由于这个位置没有被更改,故它至少与一个相邻的位置颜色一致,根据性质1不难推出)。且在下一次中它的相邻位置也不会被更改(与该位置同色的位置显然不会被更改,不同色的位置如果被修改成了相同的位置那么就又会形成连续的一段,如果没有被修改那么就一定存在另一个同色段将它包含)
因此我们找到所有一开始就不会变的位置进行\(bfs\),储存下每个位置最后一次变化的操作数,与\(k\)进行比较即可
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<vector> #include<math.h> #include<queue> #include<set> #include<map> using namespace std; typedef long long ll; typedef long double db; typedef pair<int,k,lst[200200]; char s[200200]; queue<int> q; char fan(char ch) { if (ch=='B') return 'W'; else return 'B'; } int read() { int x=0,f=1;char ch=getchar(); while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();} while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();} return x*f; } int main() { n=read();k=read(); scanf("%s",s); memset(lst,0x3f,sizeof(lst)); rep(i,n-1) { int l=(i-1+n)%n,r=(i+1)%n; if ((s[i]==s[l]) || (s[i]==s[r])) { //cout << "push " << i << endl; lst[i]=0;q.push(i); } } while (!q.empty()) { int now=q.front();q.pop(); //cout << now << endl; int l=(now-1+n)%n,r=(now+1)%n; if (lst[l]>maxd) { lst[l]=lst[now]+1;q.push(l); } if (lst[r]>maxd) { lst[r]=lst[now]+1;q.push(r); } } rep(i,n-1) { if (lst[i]>k) lst[i]=k; if (lst[i]&1) s[i]=fan(s[i]); } rep(i,n-1) putchar(s[i]); return 0; }
G
题面一长串只有最后两行有用
不难得出\(min(sum)=\frac{n(n+1)}{2}\),如果\(k\)小于这个值则无解。否则我们将会调整排列\(q\)来增大这个\(sum\)
考虑固定\(p_i=i\)然后寻找对应的\(q\).维护两个指针\(l,r\),\(l\)从小到大\(r\)从大到小扫。如果当前这个位置放\(r\)可行那么就放\(r\),否则就放\(l\)。不难发现这样放只要\(k\)不超过最大的可能值就必然能找到\(sum\)恰好等于\(k\)的情况。由于在扫的过程中必有\(p_i\geq l\),且\(p_i\)一直在增大,故\(r-p_i\)一直在减小,因此在填完了一次\(l\)之后总能找到一个位置\(r\)使得用完所有的剩余空间。
#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<algorithm> #include<vector> #include<math.h> #include<queue> #include<set> #include<map> using namespace std; typedef long long ll; typedef long double db; typedef pair<int,p[1001000],q[1001000]; ll k; int read() { int x=0,&k); if (k<1ll*(n+1)*n/2) {puts("-1");return 0;} rep(i,n) p[i]=i; int l=1,r=n;ll now=1ll*(n+1)*n/2; rep(i,n) { if ((r>=p[i]) && (now+r-p[i]<=k)) { now+=(r-p[i]); q[i]=r;r--; } else { q[i]=l;l++; } } printf("%lld\n",now); rep(i,n) printf("%d ",p[i]);puts(""); rep(i,q[i]);puts(""); return 0; }