当先锋百科网

首页 1 2 3 4 5 6 7

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;
  }