按照题目要求写出cmp函数,sort一下就行了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
int d,y,id;
}a[1100000];
int n;
int cmp(node a,node b)
{
if (a.d!=b.d) return a.d>b.d;
if (a.y!=b.y) return a.y<b.y;
return a.id<b.id;
}
int main()
{
while (scanf("%d",&n)==1)
{
for (int i=0;i<n;i++)
{
int x,y;
scanf("%d %d",&x,&y);
a[i].d=x-y,a[i].y=y,a[i].id=i;
}
sort(a,a+n,cmp);
for (int i=0;i<n;i++)
{
if (i!=0) printf(" ");
printf("%d",a[i].id);
}
printf("\n");
}
return 0;
}
我们把前缀和 s[i] ,从后往前依次插入到set里,如果当前下标为奇数,我们需要找set中是否存在一个数 x ,使得 x−s[i]=−k ,即 x=−k+s[i] ;如果当前下标为偶数,我们需要找set中是否存在一个数 x ,使得 x−s[i]=k ,即 x=k+s[i] 。卡着内存过的。。。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
typedef long long LL;
int T;
LL a[1100000],s[1100000];
int n,cas;
LL k;
set<LL> S;
int main()
{
scanf("%d",&T);
while (T--)
{
S.clear();
int flag=0;
scanf("%d %I64d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%I64d",&a[i]);
for (int i=1;i<=n;i++)
{
if (i&1) s[i]=s[i-1]+a[i];
else s[i]=s[i-1]-a[i];
}
for (int i=n;i>=0;i--)
{
S.insert(s[i]);
if (i&1)
{
if (S.count(-k+s[i])==1)
{
flag=1;
break;
}
}
else
{
if (S.count(k+s[i])==1)
{
flag=1;
break;
}
}
}
if(flag) printf("Case #%d: Yes.\n",++cas);
else printf("Case #%d: No.\n",++cas);
}
return 0;
}
首先判断已有的括号序列是否合法,以及n是否为奇数。我们设已有的括号序列中有a个左括号,b个右括号。因为总序列长度为n,我们设m=n/2,那么最终的括号序列有m个左括号和m个右括号。题目的答案相当于从(a,b)到(m,m)且不超过y=x这条线的方案数。很容易发现,这个答案相当于找从(0,0)到(p,q)且不超过y=x这条线的方案数,p=m-a,q=m-b。这个答案就相当于(0,-1)到(p,q-1)切与y=x这条线没有交点的方案数。因为从(0,-1)到(d,d)的方案数相当于从(-1,0)到(d,d)的方案数,则不合法的答案数相当于从(-1,0)到(p,q-1)且与y=x有至少一个交点的答案数,很容易发现,从(-1,0)到(p,q-1)的路线必与(p,q-1)有交点,所以不合法的答案数即为从(-1,0)到(p,q-1)的路线数。则原答案为
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
int l,n;
char s[1100000];
LL inv[1100000],ff[1100000],f[1100000];
int flag,tail;
LL a,b;
LL C(int n,int m)
{
LL res=(f[n]*inv[m])%mod;
res=(res*inv[n-m])%mod;
return res;
}
int main()
{
f[0]=1;
for (int i=1;i<=1000010;i++)
f[i]=(f[i-1]*i)%mod;
ff[1]=ff[0]=inv[1]=inv[0]=1;
for (int i=2;i<=1000010;i++)
{
inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
ff[i]=inv[i];
}
for (int i=2;i<=1000010;i++)
inv[i]=(inv[i-1]*inv[i])%mod;
while (scanf("%d",&n)==1)
{
scanf("%s",s);
l=strlen(s);
flag=0;
a=b=0;
if (n&1)
{
printf("0\n");
continue;
}
tail=0;
for (int i=0;i<l;i++)
if (s[i]=='(') tail++,a++;
else
{
b++;
if (tail==0)
{
flag=1;
break;
}
tail--;
}
if (flag)
{
printf("0\n");
continue;
}
LL m=n/2;
LL p=m-a,q=m-b;
LL ans=C(a+b,a);
ans=(ans*(p-q+1))%mod;
ans=(ans*ff[p+1])%mod;
cout<<ans<<endl;
}
return 0;
}
很容易发现, x1 到 xn 中最多只有1~ n−−√ 这些数。我们设dp[i][j]表示利用前i种数字到达和j的方案数。那么dp[i][j]=dp[i][j-i]+dp[i-1][j-i]。表示前一个数是i或者i-1。O(n* n−−√ )的时间内可以得到答案。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int T,cas;
int n,m;
int dp[400][51000];
int ans;
int main()
{
cin>>T;
while (T--)
{
cin>>n>>m;
dp[0][0]=1;
ans=0;
for (int i=1;i*i<=2*n;i++)
{
for (int j=i;j<=n;j++)
dp[i][j]=(dp[i-1][j-i]+dp[i][j-i])%m;
ans=(ans+dp[i][n])%m;
}
printf("Case #%d: %d\n",++cas,ans);
}
return 0;
}