1004传送门
题意:求\(\sum_{i=1}^n\) \(\mid\)a[i] * x+b[i]\(\mid\)=C(其中1<=ai<=1000,-1000<=b[i]<=1000)的所有解,如果解有无穷个则输出-1
题解:由于a[i]>=1,所以\(\mid\)a[i] * x+b[i]\(\mid\)的值在x=-b[i]/a[i]左边时==-a[i] * x-b[i],在x=-b[i]/a[i]右边时==a[i] * x+b[i],所以可以按照零点位置将n个绝对值式子排序,将数轴以这些点为界限分成若干区间,从左到右按顺序处理即可
#include
using namespace std;
//#define debug(x) cout<<#x<<" is "<aa.a*bb.b;
}
ll gcd(ll x,ll y){
if(y==0)return x;
return gcd(y,x%y);
}
int main(){
int t;
scanf("%d",&t);
while(t--){
ll n,c;
scanf("%lld%lld",&n,&c);
for(int i=1;i<=n;i++)scanf("%lld%lld",&p[i].a,&p[i].b);
sort(p+1,p+1+n,cmp);
ll s1=0;
ll s2=0;
int f=1;
int tot=0;
for(int i=1;i<=n;i++){s1-=p[i].a;s2-=p[i].b;}
if(s1==0&&s2==c){f=0;printf("-1\n");continue;}
if((s1>0&&(c-s2)*(p[1].a)<=(-s1*p[1].b))||(s1<0&&(c-s2)*(p[1].a)>=(-s1*p[1].b))){
if(c-s2==0){s1=1;}
ans1[++tot]=s1;
ans2[tot]=c-s2;
}
int j;
for(int i=1;i<=n;i=j){
j=i;
while(j<=n&&p[j].a*p[i].b==p[j].b*p[i].a){s1+=2*p[j].a;s2+=2*p[j].b;j++;}
if(s1==0&&s2==c){f=0;break;}
if(((j==n+1)||((s1>0&&(c-s2)*(p[j].a)<=(-s1*p[j].b))||(s1<0&&(c-s2)*(p[j].a)>=(-s1*p[j].b))))&&(((s1>0&&(c-s2)*(p[i].a)>=(-s1*p[i].b))||(s1<0&&(c-s2)*(p[i].a)<=(-s1*p[i].b))))){
if(tot){
if(ans2[tot]*s1==ans1[tot]*(c-s2))continue;
}
if(c-s2==0){s1=1;}
ans1[++tot]=s1;
ans2[tot]=c-s2;
}
}
if(f==0)printf("-1\n");
else{
printf("%d",tot);
for(int i=1;i<=tot;i++){
if(ans2[i]==0){printf(" 0/1");}
else{
int xx=gcd(ans1[i],ans2[i]);
int sgn=1;
if(ans2[i]*ans1[i]<0)sgn=-1;
printf(" %lld/%lld",sgn*abs(ans2[i]/xx),abs(ans1[i]/xx));
}
}
printf("\n");
}
}
return 0;
}
1005传送门
题意:求出一个1到n的n个数字的一个排列并且这个排列p[i+1]-p[i]的字典序第k小
题解:使用如下dfs直接搜索p[i+1]-p[i]的值可以比较容易地找到字典序第k小的方案,重点在于复杂度的分析(代码下方附上我的分析..如有错误望指正(>_<)..)
#include
using namespace std;
//#define debug(x) cout<<#x<<" is "<
复杂度分析:由界定条件 for(int i=1-n-sum+max(0,maxx);i<=n-sum-1+min(minn,0);i++)保证这个dfs每次搜索的是一个p[i+1]-p[i]的排列,也就是不会出现搜索到无用结点的情况,每个结点最后都通向至少一个可行解,又由于只会搜索前k小的字典序,所以只有k个叶子结点,而每个被搜索到的结点都至少会被一个叶子结点经过,并且每个叶子结点到根的距离是n,所以至多会有kn个结点,而每个结点的复杂度为n,所以总的时间复杂度为O(kn*n)
1006传送门
题意:求以\(\sum_{i=1}^(n-1)\)F(i),其中F(i)表示以s[i]开头的字符串与s[0]开头的字符串的相同前缀的长度
题解:exkmp裸题
#include
#include
#include
#include
#include
using namespace std;
char sa[1100000],sb[1100000];
int lena,lenb;
typedef long long ll;
ll p[1100000],ex[1100000];
//p数组是用来让B串自己匹配自己的
void exkmp()
{
p[1]=lenb;
int x=1;
while(sb[x]==sb[x+1]&&x+1<=lenb) x++;//因为我们p[1]是具有一定性,所以我们不能直接用,所以要先暴力求出p[2]
p[2]=x-1;
int k=2;
for(int i=3;i<=lenb;i++)
{
int pp=k+p[k]-1,L=p[i-k+1];//pp实际上是p
if(i+Llena)ans--;}// printf("%d ",ex[i]);
printf("%lld\n",ans);
}
return 0;
}
1007传送门
题意:求题设要求的某种排列的方案数
题解:打表
#include
using namespace std;
#define debug(x) cout<<#x<<" is "<
打表代码
#include
using namespace std;
#define debug(x) cout<<#x<<" is "<2){f=0;break;}
}
if(f){
ac++;
}
}while(next_permutation(a+1,a+1+tot));
printf("%d\n",ac);
}
return 0;
}