A
题意
水杯1有AmL的容量,且已装了BmL的水。水杯2有CmL的水。问水杯2最少留多少水?
思路
模拟。水杯2可向水杯1转移max(C,(A-B)),所以最少留max(0,C-(A-B))
#include<bits/stdc++.h> using namespace std; int a,b,c; int main(){ scanf("%d%d%d",&a,&b,&c); printf("%d",max(0,c-(a-b))); }
B
题意
求1-n中位数为奇数的数字的数量
思路
模拟。计算每个奇数位在<=n的情况下可取的数
#include<bits/stdc++.h> using namespace std; int n,now=1,ans; int main(){ scanf("%d",&n); for (int i=1;i<=5;i++){ if (i&1) ans+=min(n,now*10-1)-(now-1); now*=10; if (n<now) break; } printf("%d\n",ans); }
C
题意
对于每个Hi执行-1或不变,问可否形成不递减序列
思路
因为要求不递减,操作又只能减,所以我们要求靠后的Hi尽可能大。逆向循环,看可否满足条件
#include<bits/stdc++.h> using namespace std; #define N (100010) int n,h[N]; int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&h[i]); for (int i=n-1;i>=1;i--){ if (h[i]<=h[i+1]) continue; else if (h[i]==h[i+1]+1) --h[i]; else{printf("No"); return 0;} } printf("Yes"); }
D
题意
1-n的每个点上都标有'L'或'R',最初每个点上都有一个小孩。执行以下操作10^100次:
如果该点上标有'L',则小孩向左移;如果该点上标有'R',则小孩向右移。
数据保证点1上为'L',点n上为'R'。
思路
模拟。由于操作次数远大于n,所以小孩毕汇聚于某个'R''L'交接处[不断向左向右],而10^100次显然是偶数,只需判断小孩走偶数次是在'R'还是'L'上即可
#include<bits/stdc++.h> using namespace std; #define ll long long #define M (1000000007) #define N (100010) int ans[N]; char a[N]; int main(){ scanf("%s",a+1); int n=strlen(a+1); int l=1; while (l<=n){ int r1=l; while (a[r1+1]=='R') ++r1; int r2=r1+1; while (a[r2+1]=='L') ++r2; for (int i=l;i<=r1;i++){ if ((r1-i)&1) ++ans[r1+1]; else ++ans[r1]; } for (int i=r1+1;i<=r2;i++){ if ((i-r1)&1) ++ans[r1+1]; else ++ans[r1]; } l=r2+1; } for (int i=1;i<=n;i++) printf("%d ",ans[i]); }
E
题意
执行以下操作[次数0~k次]:选取i与j(i≠j),将a[i]+1,a[j]-1;
求操作完毕后序列a的最大公约数
思路
无论执行几次,序列a的总和都是不变的,所以GCD*x=∑a[i](1<=i<=n) [x∈Z]
所以答案必然是∑a[i]的因子
枚举∑a[i]的因子,一部分的数减小,一部分的数增大,看操作次数是否<=k
#include<bits/stdc++.h> using namespace std; #define ll long long #define M (1000000007) #define N (510) int n,k,a[N],sum,son[30000],cha[N]; void solve(int x){ for (int i=1;i*i<=x;i++) if (x%i==0){ son[++son[0]]=i; if (x/i!=i) son[++son[0]]=x/i; } } bool check(int x){ int cnt=0,have=k; for (int i=1;i<=n;i++){ int t=a[i]%x; if (t==0) continue; cha[++cnt]=t; } sort(cha+1,cha+1+cnt); int l=1,r=cnt; while (l<r){ int t=min(cha[l],x-cha[r]); if (have<t) return 0; have-=t; cha[l]-=t; if (!cha[l]) ++l; cha[r]+=t; if (cha[r]==x) --r; } return 1; } int main(){ scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) scanf("%d",&a[i]),sum+=a[i]; solve(sum); sort(son+1,son+1+son[0]); for (int i=son[0];i>=1;i--){ if (check(son[i])){ printf("%d",son[i]); return 0; } } }
F
题意
求∑F[T] [T是S集合非空子集] [F[T]:T中min-x,min-y,max-x,max-y所形成的矩阵可涵盖S集合中的点的数目]
思路
容斥+树状数组。先假设每个点都可被每个集合覆盖,再减去x都比当前点小/大的点,y都比当前点小/大的点,再加回多减的集合[x,y都在a[i]一侧的点]
#include<bits/stdc++.h> using namespace std; #define ll long long #define M (998244353) #define N (200010) struct data{ int x,y; }a[N]; int n,ans,pow2[N]={1}; struct tree{ int a[N]; void clear(){memset(a,0,sizeof(a));} void update(int x){ for (int i=x;i<=n;i+=i&-i) ++a[i]; } int query(int x){ int res=0; for (int i=x;i;i-=i&-i) res+=a[i]; return res; } }tr; bool cmpx(data o1,data o2){return o1.x<o2.x;} bool cmpy(data o1,data o2){return o1.y<o2.y;} int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y); for (int i=1;i<=n+1;i++) pow2[i]=pow2[i-1]*2%M; ans=1ll*n*(pow2[n]-1)%M;//假设每个点都出现在所有集合中 sort(a+1,a+1+n,cmpx); for (int i=1;i<=n;i++){//减去所有构成元素的x都比a[i].x小/大的集合 ans=(ans-(pow2[i-1]-1)+M)%M;//<x ans=(ans-(pow2[n-i]-1)+M)%M;//>x a[i].x=i; } sort(a+1,a+1+n,cmpy); for (int i=1;i<=n;i++){//减去所有构成元素的y都比a[i].y小/大的集合 ans=(ans-(pow2[i-1]-1)+M)%M;//<y ans=(ans-(pow2[n-i]-1)+M)%M;//>y a[i].y=i; } for (int i=1;i<=n;i++){//加上y<a[i].y且x都比a[i].x小/大的集合 int t=tr.query(a[i].x-1); ans=(ans+(pow2[t]-1))%M;//<x <y ans=(ans+(pow2[i-1-t]-1))%M;//>x <y tr.update(a[i].x); } tr.clear(); for (int i=n;i>=1;i--){//加上y>a[i].y且x都比a[i].x小/大的集合 int t=tr.query(a[i].x); ans=(ans+(pow2[n-i-t]-1))%M;//>x >y ans=(ans+(pow2[t]-1))%M;//<x >y tr.update(a[i].x); } printf("%d",(ans+M)%M); } //容斥