A. Anton and Polyhedrons
直接统计+答案就可以了。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 1000 #define LL long long using namespace std; char s[10000]; int main() { int n; LL sum=0; scanf("%d",&n); while (n--) { scanf("%s",s); if (s[0]=='T') sum+=4; if (s[0]=='C') sum+=6; if (s[0]=='O') sum+=8; if (s[0]=='D') sum+=12; if (s[0]=='I') sum+=20; } printf("%I64d ",sum); return 0; }
算最大间隔。直接记录第一类第二类的最小的右端点和最大左端点。
然后答案就是第一类最大左端点-第二类最小右端点,第二类最大左端点-第一类最小右端点。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 1000 #define LL long long #define inf 1000000000 #define rep(i,l,r) for(int i=l;i<=r;i++) using namespace std; int main() { int n,m,max1=-inf,min1=inf,max2=-inf,min2=inf; scanf("%d",&n); rep(i,1,n) { int j,k; scanf("%d %d",&j,&k); max1=max(max1,j); min1=min(min1,k); } scanf("%d",&m); rep(i,1,m) { int j,k; scanf("%d %d",&j,&k); max2=max(max2,j); min2=min(min2,k); } int ans=0; ans=max(ans,max1-min2); ans=max(ans,max2-min1); printf("%d ",ans); return 0; }
首先分情况,如果n=1第一天就gg,n<=m,那第n才就gg,主要是n>=m的情况
首先前m天一定是满的,然后m+1天后每天减少等差数列颗,假设答案为x,则(1+(x-m))*(x-m)/2+x+1>=n,满足的最小的x+1就是答案,化简一下然后直接算就可以啦。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 1000 #define LL long long #define inf 1000000000 #define rep(i,l,r) for(int i=l;i<=r;i++) using namespace std; int main() { LL n,m; scanf("%I64d %I64d",&n,&m); if (!n) printf("0 "); else if (n==1) printf("1 "); else if (n<=m) printf("%I64d ",n); else { LL sum=m; LL now=sqrt((n-m-1)*2)+1; while ((now+2)*(now-1)>=(n-m-1)*2) now--; // printf("%I64d %I64d ",now,now*(now*3)); sum+=now+1; printf("%I64d ",sum); } return 0; }
最不会的数学题,看了评论区的题解才知道怎么写……
加个逆元就可以啦。
#include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #define rep(i,l,r) for(int i=l;i<=r;i++) #define dow(i,l,r) for(int i=r;i>=l;i--) #define maxn 400100 #define LL long long #define mm 1000000007 using namespace std; char s[maxn]; LL f1[maxn],f2[maxn],inv[maxn]; int main() { scanf("%s",s); inv[1]=1; rep(i,2,maxn-1) inv[i]=mm-(mm/i)*inv[mm%i]%mm; f1[0]=f2[0]=f1[1]=f2[1]=1; rep(i,2,maxn-1) f1[i]=f1[i-1]*(LL)(i)%mm,f2[i]=f2[i-1]*inv[i]%mm; int len=strlen(s); int l=0,r=len-1; while (l<=r && s[l]==')') ++l; while (l<=r && s[r]=='(') --r; LL sum=0; int now1=0,now2=0; rep(i,l,r) if (s[i]==')') ++now2; rep(i,l,r) { if (s[i]=='(' && now2) sum=(sum+f1[now1+now2]*f2[now2-1]%mm*f2[now1+1]%mm)%mm,now1++; else now2--; } printf("%I64d ",sum); return 0; }
题目是说每次交换两位置上的数,求当前逆序对的数量。
显然就是个树套树啦,不过太久没写就没写23333。树状数组套权值线段树。权值线段树用数组写开了20000000的大小才给过,看来要学习指针写法(p党的残念)。另外还得学会cdq分治的写法。
#include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #define rep(i,l,r) for(int i=l;i<=r;i++) #define dow(i,l,r) for(int i=r;i>=l;i--) #define maxn 400100 #define maxm 20001000 #define LL long long #define mm 1000000007 using namespace std; int size[maxm],lson[maxm],rson[maxm],num[maxn],bit[maxn],n,total; int addson() {return ++total;} int lowbit(int x) {return x&(-x);} void add(int &x,int l,int r,int y,int z) { if (!x) x=addson(); size[x]+=z; if (l==r) return; int mid=(l+r)>>1; if (y<=mid) add(lson[x],l,mid,y,z); else add(rson[x],mid+1,r,y,z); } int ask(int x,int l,int r,int y) { if (!x) return 0; if (l==r) return size[x]; int mid=(l+r)>>1; if (y<=mid) return ask(lson[x],l,mid,y); else return size[lson[x]]+ask(rson[x],mid+1,r,y); } LL bigask(int x,int y) { LL now=0; while (x) { now+=ask(bit[x],1,n,y); x-=lowbit(x); } return now; } void bigadd(int x,int y,int z) { while (x<=n) { add(bit[x],1,n,y,z); x+=lowbit(x); } } int main() { int m; scanf("%d %d",&n,&m); LL sum=0; rep(i,1,n) bigadd(i,num[i]=i,1); while (m--) { int l,r; scanf("%d %d",&l,&r); if (l==r) { printf("%I64d ",sum); continue; } if (l>r) swap(l,r); if (r-l>1) { sum-=2*(bigask(r-1,num[l])-bigask(l,num[l])); sum+=2*(bigask(r-1,num[r])-bigask(l,num[r])); } if (num[l]<num[r]) ++sum;else --sum; printf("%I64d ",sum); bigadd(l,num[l],-1); bigadd(l,num[r],1); bigadd(r,num[r],-1); bigadd(r,num[l],1); swap(num[l],num[r]); } return 0; }