2015 Damascus Collegiate Programming Contest (DCPC 2015) F~J
文章目录
F Print Mix Strings
现在有两个字符串,要求打印出所有不同的合成串。合成规则如下:
1,两个字符串作为合成后的字符串里含有的两个子串
2,除了这两个子串,合成后的字符串没有其他字符
3,重复的字符串算同一个
请你把所有的合成串输出
dfs搜索,遍历每一位是用第一个字符串的下一个位置还是第二个字符串,长度达到两个字符串之和的时候记录
用set记录合成的字符串避免重复
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
inline long long read()
{
long long kk=0,f=1;
char cc=getchar();
while(cc<'0'||cc>'9'){if(cc=='-')f=-1;cc=getchar();}
while(cc>='0'&&cc<='9'){kk=(kk<<1)+(kk<<3)+cc-'0';cc=getchar();}
return kk*f;
}
set<string>ss;string s1,s2,s3;int c1,c2,l1,l2;
void doit(int x)
{
if(c1<l1)
{
s3[x]=s1[c1];c1++;doit(x+1);c1--;
}
if(c2<l2)
{
s3[x]=s2[c2];c2++;doit(x+1);c2--;
}
if(x==l1+l2)
{
ss.insert(s3);
//cout<<s3<<endl;
return;
}
return;
}
int main()
{
int T=read();
while(T--)
{
cin>>s1>>s2;s3=s1+s2;
ss.clear();c1=c2=0;l1=s1.length();l2=s2.length();
doit(0);
for(set<string>::iterator it=ss.begin();it!=ss.end();++it)
{
string go=*it;int ll=go.length();
if(ll==l1+l2)cout<<go<<endl;
}
cout<<endl;
}
}
G Count Mix Strings
与F题相同的背景,直接给两个字符串长度,求合成串的个数
简单的排列组合问题,相当于有n+m个空选n个空放第一个字符串,其余放第二个。答案显然是C(n,n+m)看数据范围,数组存会爆,用逆元求。先开数组求出范围内所有阶乘的数值。在用公式,除法的时候求逆元。在要小心的是n+m的范围,所以数组大小是题目里n的范围的两倍。
#include<bits/stdc++.h>
#define NMAX 0x7fffffff
using namespace std;
typedef long long LL;
inline long long read()
{
long long kk=0,f=1;
char cc=getchar();
while(cc<'0'||cc>'9'){if(cc=='-')f=-1;cc=getchar();}
while(cc>='0'&&cc<='9'){kk=(kk<<1)+(kk<<3)+cc-'0';cc=getchar();}
return kk*f;
}
LL jie[20111],niy[21009];
LL mod=1000000007;
LL qc(LL a1,LL b1)
{
LL asd1=0;
while(b1)
{
if(b1&1)asd1=(asd1+a1)%mod;
b1>>=1;a1=(a1+a1)%mod;
}
return asd1;
}
void exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b){x=1;y=0;return;}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
LL ni(LL a)
{
LL nia,y;
exgcd(a,mod,nia,y);
return (nia%mod+mod)%mod;
}
int main()
{
int T=read();jie[1]=1;niy[1]=ni(1);
for(int i=2;i<=20009;++i)
{
jie[i]=qc(jie[i-1],i);niy[i]=ni(jie[i]);
}
while(T--)
{
int n=read(),m=read();LL asd;
asd=qc(niy[m],niy[n]);
asd=qc(asd,jie[n+m]);
cout<<asd<<endl;
}
}
H tourists
两种船,价钱分别为c1,c2,载客量分别为a,b。
求能否分别有x,y艘船载客n人使得总价最少
显然求 ax+by=n的所有解里代价最少的一个(一元线性同余方程)用扩展欧几里得求出特解一个后继续求通解,求出正整数范围内的每一个解时用maxi记录代价最小的那一个组合,并更新。
#include<bits/stdc++.h>
#define NMAX 0x7fffffff
using namespace std;
typedef long long LL;
inline long long read()
{
long long kk=0,f=1;
char cc=getchar();
while(cc<'0'||cc>'9'){if(cc=='-')f=-1;cc=getchar();}
while(cc>='0'&&cc<='9'){kk=(kk<<1)+(kk<<3)+cc-'0';cc=getchar();}
return kk*f;
}
struct zj
{
LL x,y;
};
LL aa,bb,c1,c2;zj maxi;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0){x=1;y=0;return a;}
LL k=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return k;
}
bool tyfc(LL a,LL b,LL c)
{
LL x,y;
maxi.x=-1;
LL d=exgcd(a,b,x,y);
if(c%d)return 0;
else
{
x*=(c/d);y*=(c/d);LL mod=b/d;
x=(x%mod+mod)%mod;
y=(c-a*x)/b;
if(y<0)return 0;
zj k;k.x=x;k.y=y;maxi=k;
while(1)
{
k.y=k.y-a/d;
if(k.y<0)break;
k.x=k.x+b/d;
if(c1*k.x+c2*k.y<c1*maxi.x+c2*maxi.y)maxi=k;
}
cout<<maxi.x<<" "<<maxi.y<<endl;
}
return 1;
}
int main()
{
LL n;
while(n=read())
{
c1=read();aa=read();c2=read();bb=read();
if(!tyfc(aa,bb,n))printf("failed\n");
}
return 0;
}
I Teleportia(队友写的)
题意:有n个传送站,覆盖范围为p(以p为半径的圆),一个传送站可以花费两秒到其覆盖
范围内的任一传送站,一个人从(xs,ys)出发到(xe,ye),两点间距离定义为曼哈顿距离,
人的速度是单位长度每秒,问最短用时
solution:求两个点之间的最短距离,从起点开始对于可传送的传送站用 2s更新,
最后跑一遍floyd
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 105
int T,n;
ll x[maxn],y[maxn],p[maxn],dis[maxn][maxn];
ll Dis(ll x1,ll y1,ll x2,ll y2)
{
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)cin>>x[i]>>y[i]>>p[i];
cin>>x[0]>>y[0]>>x[n+1]>>y[n+1];
p[0]=p[n+1]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=abs(x[i]-x[j])+abs(y[i]-y[j]);
for(int i=1;i<=n;i++)
dis[0][i]=abs(x[i]-x[0])+abs(y[i]-y[0]),
dis[i][n+1]=abs(x[n+1]-x[i])+abs(y[n+1]-y[i]);//预处理距离
dis[0][n+1]=abs(x[n+1]-x[0])+abs(y[n+1]-y[0]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(Dis(x[i],y[i],x[j],y[j])<=1ll*p[i]*p[i])dis[i][j]=min(dis[i][j],2ll);//对于能传送的则用2更新
for(int k=0;k<=n+1;k++)
for(int i=0;i<=n+1;i++)
for(int j=0;j<=n+1;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);//floyd
cout<<dis[0][n+1];
}
return 0;
}
J palprime(队友写的)
题意:给出一个整数b,找到不小于b的最小整数n,使得n是素数且二进制表示是回文的
solution:暴力枚举符合条件的数
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 5050
int a[33],b[maxn],res;
char s[33];
bool check(int m)//判断是否为素数
{
for(int i=2;i*i<=m;i++)
if(m%i==0)return 0;
return 1;
}
void init()
{
res=0;
for(int n=2;n<=22;n++)
{
a[1]=a[n]=1;
int N=1<<((n-1)/2);
for(int i=0;i<N;i++)
{
for(int j=0;j<(n-1)/2;j++)
if(i&(1<<j))a[j+2]=1;
else a[j+2]=0;
for(int j=n-1;j>n/2;j--)
a[j]=a[n+1-j];
int temp=0;
for(int j=1;j<=n;j++)temp=2*temp+a[j];
if(check(temp))b[res++]=temp;//先处理前半段,后半段回文
}
}
sort(b,b+res);
}//预处理回文的素数
int main()
{
init();
while(~scanf("%s",s))
{
int temp=0,len=strlen(s);
for(int i=0;i<len;i++)temp=2*temp+s[i]-'0';
int pos=lower_bound(b,b+res,temp)-b;
int n=b[pos],cnt=0;
while(n)a[cnt++]=n%2,n/=2;
for(int i=cnt-1;i>=0;i--)
printf("%d",a[i]);
printf("\n");
}
return 0;
}