20181214第一周周训思路整理

第一周题解

训练时间:2018/12/14-2018/12/21 author:wlxsq

Problem List
  • BZOJ4300: 绝世好题 Problem link
  • Bailian1308: Is It A Tree? Problem link
  • HDU2594: Simpsons’ Hidden TalentsProblem link
  • POJ1511:Invitation Cards Problem link
  • POJ1751:HighwaysProblem link
  • HDU2089:不要62Problem link
  • BZOJ4355:Play with SequenceProblem link
  • BZOJ1257:余数之和Problem link
  • POJ2061:青蛙的约会Problem link
  • BZOJ1601:[N/A]Problem link

Problem Answer
  • BZOJ4300:绝世好题 链接
/*
	BZOJ4300:绝世好题 
	一道很不错的动归题
	普通想法dp[i]表示以i作为结束的最长长度,类似于最长上升子序列O(n^2)的思路。
	很显然,这种做法是会TLE的。
	但是这题有不能够像LIS那样有O(nlogn)的时间复杂度做法,因为他要做与运算,会有后效性。 
	正解:
	dp	1 2 3 ... 31	表示对应的二进制位的最长长度
		0 0 0 ... 0
	对于每一个b[i],其b[i-1]二进制位只要有一位不为0,则b[i]&b[i-1]!=0
	所以只要找到b[i]二进制位出现的最长长度,更新就好。 
*/ 
#include
#include
#include 
#include
#include 
using namespace std;
const int N = 100005;
int a[N];
int dp[100];	//	dp[i]表示二进制位i位置上的最长长度。 
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}
	return f*x;
}
int main()
{
	int n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++)
	{
		int tmp=0; 
		for(int j=0;j<=30;j++)	//	找出与运算之后不为0的最长长度 
		{
			if(a[i]&(1<

完成时间:2018/12/12 14:12

  • Bailian1308: Is It A Tree? 链接
/*
	给出一副图,判断是否能够形成一棵树。
	并查集处理即可。 
	1、存在环,
	2、只有一个根节点(点的个数=边的个数+1) 
	3、直接输入0 0表示一颗空树,is a tree
	4、题目没有给出数据范围,所有只能尽可能的开大一点 
*/
#include
#include
#include
#include 
using namespace std;
const int N = 1000005;
int f[N],Case=1,a,b,flag,cnt_v,cnt_e;
mapMap;
int Find(int x)
{
	while(f[x]!=x) return f[x]=Find(f[x]);
	return f[x];
}
void init()
{
	flag=1,cnt_v=cnt_e=0;
	for(int i=0;i>a>>b;
		if(a||b)
		{
			if(Map[a]==0) cnt_v++;
			if(Map[b]==0) cnt_v++;
			cnt_e++;Map[a]++,Map[b]++;
		}
		if(a==-1&&b==-1) break;
		else if(a==0&&b==0)
		{
			if(cnt_v&&(cnt_v!=cnt_e+1))flag=0;
			if(flag) printf("Case %d is a tree.\n",Case++);
			else printf("Case %d is not a tree.\n",Case++);
			init();
		}else 
		{
			int x=Find(a),y=Find(b);
			if(x==y) flag=0;
			if(flag) f[x]=y;
		}
	}while(1);
	return 0;
}

完成时间:2018/12/12 15:40

  • HDU2594: Simpsons’ Hidden Talents链接
/*
	给出两个字符串S1和S2,求S1的前缀和S2的后缀最长公共长度。
	s1和s2的长度为len:50000。
	暴力做法时间复杂度:O(len^2)
	深入理解KMP的next数组。
	求next数组时间复杂度:O(len) 
	next[i]表示子串[0,i-1]的前后缀匹配的最长长度 
	注意:
		1、aaa aaa 
*/ 
#include
#include
#include
#include
using namespace std;
const int N = 1000005;
int nxt[N];
string s1,s2;
int min(int a,int b)
{
	return a>b?b:a;
}
void get_next(string s)
{
	int j=0,k=-1,len=s.size();
	nxt[0]=-1;
	while(j>s1>>s2) get_next(s1+s2);
	return 0;
} 

完成时间:2018/12/12 16:35

  • POJ1511:Invitation Cards 链接
#pragma GCC optimize(2)
/*
	这个题目还是比较简单的,思考难度不大
	求从一个点出发,到达其余所有的点路径之和
	再求从其余所有点回到出发点的路径之和
	注意:
		1、N=M=1000000
			O(n^2)的时间复杂度肯定是过不了的,得O(nlogn)
		全部都是正数,堆+dijkstra完美解决问题。
		2、常数太大。。。vector<>死活TLE... 故手写邻接表
*/
#include
#include
#include
#include
#include
using namespace std;
const long long N = 1000015;
long long dist1[N],dist2[N];
typedef pairP;
vector

G1[N],G2[N]; int t,n,m,u,v,w; const long long INF= 1e15; inline long long read() { long long x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();} return f*x; } struct Edge { int nxt,to; long long w; }E1[N],E2[N]; int cnt1=0,cnt2=0,head1[N],head2[N]; void add1(int u,int v,long long w) { E1[++cnt1].nxt=head1[u]; E1[cnt1].to=v; E1[cnt1].w=w; head1[u]=cnt1; } void add2(int u,int v,long long w) { E2[++cnt2].nxt=head2[u]; E2[cnt2].to=v; E2[cnt2].w=w; head2[u]=cnt2; } struct cmp { bool operator()(const P p1,const P p2) { return p1.first > p2.first; } }; priority_queue,greater

>q; inline long long dij1() { for(int i=0;i<=n;i++) dist1[i]=INF;dist1[1]=0; while(!q.empty()) q.pop(); q.push(P(0,1)); while(!q.empty()) { P tt=q.top();q.pop(); u=tt.second; if(tt.first!=dist1[u]) continue; for(register int i=head1[u];i;i=E1[i].nxt) { int v=E1[i].to;long long w=E1[i].w; if(dist1[v]>dist1[u]+w) { dist1[v]=dist1[u]+w; q.push(P(dist1[v],v)); } } } long long res=0; for(register int i=1;i<=n;i++) res+=dist1[i],G1[i].clear(); return res; } inline long long dij2() { for(int i=0;i<=n;i++) dist2[i]=INF;dist2[1]=0; while(!q.empty()) q.pop(); q.push(P(0,1)); while(!q.empty()) { P tt=q.top();q.pop(); u=tt.second; if(tt.first!=dist2[u]) continue; for(register int i=head2[u];i!=0;i=E2[i].nxt) { int v=E2[i].to;long long w=E2[i].w; if(dist2[v]>dist2[u]+w) { dist2[v]=dist2[u]+w; q.push(P(dist2[v],v)); } } } long long res=0; for(register int i=1;i<=n;i++) res+=dist2[i],G2[i].clear(); return res; } int main() { // freopen("invite.in","r",stdin); // scanf("%d",&t); t=read(); while(t--) { n=read();m=read(); cnt1=cnt2=0; memset(head1,0,sizeof(head1)); memset(head2,0,sizeof(head2)); // scanf("%d%d",&n,&m); for(register int i=0;i

完成时间:2018/12/13 13:21

  • POJ1751:Highways链接
/*
	最小生成树题
	Kruskal	时间复杂度:O(ElogE)
	Prim	时间复杂度:O(n^2) O(nlogn)
*/
#include
#include
#include
#include
#define INF 1e9
using namespace std;
const int N = 1005;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+(ch-'0');ch=getchar();}
	return f*x;
}
struct node
{
	int x,y;
}V[N];
int Map[N][N];
int dist[N];
int vis[N];
int pre[N];
int n,m,x,y;
double MST;
void prim()
{
	for(int i=1;i<=n;i++) pre[i]=1,dist[i]=Map[1][i];dist[1]=0;
	vis[1]=1;
	for(int i=2;i<=n;i++)
	{
		int v=-1;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&(v==-1||dist[v]>dist[j])) v=j;
		if(v==-1) break;
		if(Map[pre[v]][v]!=0)cout<Map[v][j])
			{
				dist[j]=Map[v][j];
				pre[j]=v;
			}
		}
	}
}
int main()
{
	memset(Map,-1,sizeof(Map));
	n=read();
	for(int i=1;i<=n;i++)
	{
		V[i].x=read();
		V[i].y=read();
	}
	m=read();
	for(int i=1;i<=m;i++)
	{
		x=read();y=read();
		Map[x][y]=Map[y][x]=0;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(Map[i][j]==-1)
			{
				int dist=(V[i].x-V[j].x)*(V[i].x-V[j].x)+(V[i].y-V[j].y)*(V[i].y-V[j].y);
				Map[i][j]=Map[j][i]=dist;
			}
		}
	}
//	cout<<"start"<

完成时间:(POJ又挂了,未AC)

  • HDU2089:不要62链接
方法一:暴力写法
/*
	数位DP模板题
	但是看数据范围,很明显是一道水题啊。
	两种方法都做一下。
*/
#include
using namespace std;
const int N = 1000005;
int f[N];
bool check(int x)
{
	int flag=0;
	while(x)
	{
		if(x%10==4) return true;
		if(flag&&x%10==6) return true;
		if(x%10==2) flag=1;
		else flag=0;
		x/=10;
	}
	return false;
}
void init()
{
	for(int i=1;i>a>>b)
	{
		if(a==0&&b==0) break;
		cout<
方法二:dfs写法
#include
using namespace std;
const int N = 15;
int dp[N][2];	//	dp[i][0/1]表示长度为i,末尾是否为6
int bit[N];
int dfs(int len,bool is6,int isMax)
{
	if(len==0) return 1;
	if(!isMax&&dp[len][is6]>0) return dp[len][is6];
	int cnt=0;
	int maxNum=isMax?bit[len]:9;
	for(int i=0;i<=maxNum;i++)
	{
		if(i==4) continue;
		if(i==2&&is6) continue;
		cnt+=dfs(len-1,i==6,isMax&&i==maxNum);
	}
	if(!isMax) dp[len][is6]=cnt;
	return cnt;
}
int solve(int x)
{
	int len=0;
	while(x)
	{
		bit[++len]=x%10;
		x/=10;
	}
	return dfs(len,false,true);
}
int main()
{
	int a,b;
	while(cin>>a>>b)
	{
		if(a==0&&b==0) return 0;
		cout<
方法三:递推式写法
/*
	dp[i][j]表示长度为i,首位为j的所有方案数
	需要注意,首位可以是0.
	预处理出所有的长度,计算即可。
*/
#include
using namespace std;
const int N = 15;
int dp[N][N];
int bit[N];
void init()
{
	dp[0][0]=1;
	for(int i=1;i=1;i--)
	{
		for(int j=0;j>a>>b)
	{
		if(a==0&&b==0) return 0;
		cout<

完成时间:

  • BZOJ4355:Play with SequenceClick me
WC2016年的题目? 好吧线段树题,有些思维难度。
代码自己写。。。
哈哈,好吧,其实是我自己写了一大半,然后懵了。。。就不想写了。。。

完成时间:

  • BZOJ1257:余数之和Click me
/*
	这是一道简单得思维题,CQOI2007
	推算:k%i=k-[k/i]*i
		sum=sig(k%i)=sig(k-[k/i]*i)=nk-sig([k/i]*i);
	k整除i,是这道题目的突破口
*/
#include
using namespace std;
int main()
{
	long long n,k,r,d;
	cin>>n>>k;
	long long ans=0;
	if(n>k) ans=(n-k)*k,n=k;
	for(long long l=1;l<=n;l=r+1)
	{
		d=k/l;
		r=k/d;	//	右区间,l为左区间
		if(r>n)r=n;
		ans+=(r-l+1)*k-(r-l+1)*(l+r)/2*d;
	}
	cout<

完成时间:

  • POJ2061:青蛙的约会Click me
/*
	很显然,设总共跳了c次相遇,
	则:我们可以写出等式(mc+x)%L=(nc+y)%L;
	令总共差了k圈
	则x+mc=y+nc+kL;
	整理可得:(n-m)*c+Lk=x-y;求解最小的c
	历史总时惊人的相似:ax+by=c;求解x
*/
#include
using namespace std;
long long exgcd(long long a,long long b,long long &x,long long &y)
{
	if(b==0)
	{
		x=1,y=0;
		return a;
	}
	long long c=exgcd(b,a%b,x,y);
	long long tmp=x; x=y; y=tmp-a/b*y;
	return c;
}
int main()
{
	long long x,y,n,m,L;
	cin>>x>>y>>m>>n>>L;
	long long a=n-m;
	long long b=L;
	long long c=x-y;
	long long gcd=exgcd(a,b,x,y);
	if(c%gcd) cout<<"Impossible"<

完成时间:

  • BZOJ1601:[N/A]Click me
思路有了,没时间写了。
最小生成树题。

完成时间:

你可能感兴趣的:(20181214第一周周训思路整理)