A.
傻逼题?。。。前缀和什么的随便搞搞就好了。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 1000050 using namespace std; int n,a[maxn],s[maxn],cnt[maxn][2]; long long ans=0; char p[maxn]; int main() { scanf("%d",&n); scanf("%s",p); for (register int i=1;i<=n;i++) { if (p[i-1]=='a') a[i]=1;else a[i]=-1; s[i]=s[i-1]+a[i]; } if (s[n]<0) cnt[-s[n]][1]++;else cnt[s[n]][0]++; for (register int i=n-1;i>=0;i--) { if (s[i]<0) {ans+=(long long)cnt[-s[i]][1];cnt[-s[i]][1]++;} else {ans+=(long long)cnt[s[i]][0];cnt[s[i]][0]++;} } printf("%lld\n",ans); return 0; }
B.
我们可以用一个单调栈。分别维护左上右上左下右下的轮廓的情况。(类似于凸包,但有点不一样)。具体还是代码能说清楚,觉得这道题好神啊。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100500 using namespace std; struct pnt { int x,y; pnt (int x,int y):x(x),y(y) {} pnt () {} }p[maxn],q[maxn<<2]; int n,top=0,m=0,st[maxn]; int read() { char ch;int data=0,f=1; while (ch<'0' || ch>'9') { if (ch=='-') f=-1; ch=getchar(); } while (ch>='0' && ch<='9') { data=data*10+ch-'0'; ch=getchar(); } return data*f; } bool cmp(pnt x,pnt y) { return x.x<y.x; } void work1() { top=0; for (int i=1;i<=n;i++) { if ((!top) || ((p[i].x!=p[st[top]].x) && (p[st[top]].y<p[i].y))) st[++top]=i; else if ((p[i].x==p[st[top]].x) && (p[i].y>p[st[top]].y)) st[top]=i; } q[++m]=p[st[top]]; for (int i=top-1;i>=1;i--) { q[++m]=pnt(p[st[i+1]].x,p[st[i]].y); q[++m]=p[st[i]]; } return; } void work2() { top=0; for (int i=1;i<=n;i++) { if ((!top) || ((p[i].x!=p[st[top]].x) && (p[i].y<p[st[top]].y))) st[++top]=i; else if ((p[i].x==p[st[top]].x) && (p[i].y<p[st[top]].y)) st[top]=i; } q[++m]=p[st[1]]; for (int i=2;i<=top;i++) { q[++m]=pnt(p[st[i]].x,p[st[i-1]].y); q[++m]=p[st[i]]; } return; } void work3() { top=0; for (int i=n;i>=1;i--) { if ((!top) || ((p[i].x!=p[st[top]].x) && (p[i].y<p[st[top]].y))) st[++top]=i; else if ((p[i].x==p[st[top]].x) && (p[i].y<p[st[top]].y)) st[top]=i; } q[++m]=p[st[top]]; for (int i=top-1;i>=1;i--) { q[++m]=pnt(p[st[i+1]].x,p[st[i]].y); q[++m]=p[st[i]]; } return; } void work4() { top=0; for (int i=n;i>=1;i--) { if ((!top) || ((p[i].x!=p[st[top]].x) && (p[i].y>p[st[top]].y))) st[++top]=i; else if ((p[i].x==p[st[top]].x) && (p[i].y>p[st[top]].y)) st[top]=i; } q[++m]=p[st[1]]; for (int i=2;i<=top;i++) { q[++m]=pnt(p[st[i]].x,p[st[i-1]].y); q[++m]=p[st[i]]; } return; } int main() { n=read(); for (int i=1;i<=n;i++) p[i].x=read(),p[i].y=read(); sort(p+1,p+n+1,cmp); work1(); work2(); work3(); work4(); printf("%d\n",m); for (int i=1;i<=m;i++) printf("%d %d\n",q[i].x,q[i].y); return 0; }
C.
朴素的爆搜是枚举每一位什么情况,然后dp判一下。
然后发现因为k很小但是位数很大,所以可以枚举0..k各有多少个。
然后加个高精就过啦。(我没加)
直接贴代码。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 505 using namespace std; long long n,k,c[maxn][maxn],a[maxn],top=0,ans=1,bit[maxn]; bool vis[maxn][maxn]; void get_C() { c[0][0]=1; for (long long i=1;i<=n;i++) { c[i][0]=1; for (long long j=1;j<=i;j++) c[i][j]=c[i-1][j-1]+c[i-1][j]; } } bool check() { long long sum=0;for (long long i=0;i<=k;i++) bit[i]=0; for (long long i=1;i<=top;i++) {bit[a[i]]++;sum+=a[i];} if (sum&1) return false; for (long long i=0;i<=top;i++) for (long long j=0;j<=sum/2;j++) vis[i][j]=false; vis[0][0]=true; for (long long i=1;i<=top;i++) for (long long j=0;j<=sum/2;j++) { if (j>=a[i]) vis[i][j]=vis[i-1][j]|vis[i-1][j-a[i]]; else vis[i][j]=vis[i-1][j]; if ((vis[i][j]) && (j==sum/2)) return true; } return false; } void get_ans() { long long ret=n,ret2=1; for (long long i=0;i<=k;i++) { ret2*=c[ret][bit[i]]; ret-=bit[i]; } ans-=ret2; } void dfs(long long bit,long long n) { if (bit==k) { for (long long i=n;i>=1;i--) a[++top]=k; if (check()) get_ans(); for (long long i=n;i>=1;i--) a[top--]=0; return; } dfs(bit+1,n);long long ret=top; for (long long i=1;i<=n;i++) { a[++top]=bit; dfs(bit+1,n-i); } while (top!=ret) a[top--]=0; } int main() { freopen("unlucky20.in","r",stdin); freopen("unlucky20.out","w",stdout); scanf("%lld%lld",&n,&k); get_C(); for (long long i=1;i<=n;i++) ans*=(k+1); dfs(0,n); printf("%lld\n",ans); return 0; }