• Codeforces Round #534 Div. 1


      A:用一列放竖着的方块,两列放横着的方块。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 1010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n;
    char s[N];
    signed main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    #endif
    	scanf("%s",s+1);n=strlen(s+1);
    	int x=0,y=0;
    	for (int i=1;i<=n;i++)
    	if (s[i]=='0')
    	{
    		x++;
    		if (x&1) cout<<1<<' '<<1<<endl;
    		else cout<<3<<' '<<1<<endl;
    	}
    	else
    	{
    		y++;if (y>4) y=1;
    		cout<<y<<' '<<2<<endl;
    	}
    	return 0;
    	//NOTICE LONG LONG!!!!!
    }
    

      B:先询问2k 2k+1,假设已经知道了a>2k,则当a>2k+1时,后者大,否则前者大。这样可以倍增出一个a的取值区间。注意到在区间内x mod a值开始单增,中间突变为0(即x=a),然后又单增,并且最开始的值要比最终的值大。于是拿2k+1和一个二分值比较即可。注意特判a=1的情况,询问0和1即可。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    char s[10];
    signed main()
    {
    	cin>>(s+1);
    	while (s[1]!='e')
    	{
    		cout<<'?'<<' '<<0<<' '<<1<<endl;
    		char c;cin>>c;
    		if (c=='x') cout<<'!'<<' '<<1<<endl;
    		else
    		{
    			int x;
    			for (int i=0;i<30;i++)
    			{
    				cout<<'?'<<' '<<(1<<i)<<' '<<(1<<i+1)<<endl;
    				cin>>c;
    				if (c=='x') {x=i;break;}
    			}
    			int y=(1<<x+1);
    			int l=(1<<x)+1,r=y-1,ans=y;
    			while (l<=r)
    			{
    				int mid=l+r>>1;
    				cout<<'?'<<' '<<mid<<' '<<y<<endl;
    				cin>>c;
    				if (c=='x') l=mid+1;
    				else ans=mid,r=mid-1;
    			}
    			cout<<'!'<<' '<<ans<<endl;
    		}
    		cin>>(s+1);
    	}
    	return 0;
    	//NOTICE LONG LONG!!!!!
    }
    

      C:二选一当然是考虑问题间有什么关系。随便找一棵dfs树,如果深度>=n/k,那么显然有一条长度为n/k的简单路径;否则由抽屉原理,至少有一层的点数超过k,由此可得树的叶子数量超过k。注意到由于每个点度数至少为3,叶子至少会往上连两条边。我们考虑对每个叶子构造一个以其为标记的环。唯一的要求是环长不能为3的倍数,由于我们有至少两条边,所以可以得到至少三个包含该叶子的环,容易发现其中一定存在一个满足要求的。并且由于环长不会超过树的深度,所以总输出量也是O(n)的。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #include<cassert>
    using namespace std;
    #define ll long long
    #define N 500010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,m,k,p[N],deep[N],fa[N],t,root=1;
    bool flag[N],isleaf[N];
    struct data{int to,nxt;
    }edge[N<<1];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void dfs(int k) 
    {
    	flag[k]=1;int son=0;
    	for (int i=p[k];i;i=edge[i].nxt)
    	if (!flag[edge[i].to])
    	{
    		deep[edge[i].to]=deep[k]+1;
    		fa[edge[i].to]=k;
    		son++;
    		dfs(edge[i].to);
    	}
    	if (son==0) isleaf[k]=1;
    }
    signed main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("c.in","r",stdin);
    	freopen("c.out","w",stdout);
    #endif
    	n=read(),m=read(),k=read();
    	for (int i=1;i<=m;i++)
    	{
    		int x=read(),y=read();
    		addedge(x,y),addedge(y,x);
    	}
    	deep[root]=1;dfs(root);
    	for (int i=1;i<=n;i++)
    	if (deep[i]>=n/k+(n%k>0))
    	{
    		cout<<"PATH"<<endl;cout<<deep[i]<<endl;
    		for (int x=i;x!=root;x=fa[x]) printf("%d ",x);
    		cout<<root;
    		return 0;
    	}
    	cout<<"CYCLES"<<endl;
    	for (int i=1;i<=n;i++)
    	if (isleaf[i])
    	{
    		bool f=0;
    		for (int j=p[i];j;j=edge[j].nxt)
    		if (edge[j].to!=fa[i]&&(deep[i]-deep[edge[j].to])%3!=2) 
    		{
    			printf("%d
    ",deep[i]-deep[edge[j].to]+1);
    			for (int x=i;x!=edge[j].to;x=fa[x]) printf("%d ",x);
    			printf("%d
    ",edge[j].to);
    			f=1;break;
    		}
    		if (!f)
    		{
    			int u=0,v=0;
    			for (int j=p[i];j;j=edge[j].nxt)
    			if (edge[j].to!=fa[i])
    				if (!u) u=edge[j].to;else if (!v) v=edge[j].to;
    				else break;
    			if (deep[u]<deep[v]) swap(u,v);
    			printf("%d
    ",deep[u]-deep[v]+2);
    			printf("%d ",i);
    			while (u!=v) printf("%d ",u),u=fa[u];
    			printf("%d
    ",v);
    		}
    		k--;if (k==0) break;
    	}
    	return 0;
    	//NOTICE LONG LONG!!!!!
    }
    

      D:先求出所有数的gcd,显然每次对一个数操作都应该去除gcd至少一种质因子,给每个数只保留这些质因子。由于值域1e12,不同的质因子数量最多为11个,设该数为m,那么所需要操作的数也不会超过m个。显然可以得到一个dp,即f[i][j][k]为前i个数操作j个质因子状态为k的最小Σe。复杂度O(n·m·3m)。

      注意到对于这m种质因子次数均相同的数,只需要保留代价最小的m个。于是先去一下重,猜想去重之后剩下数的数量就不会特别多。但乘上m·3m后还是跑不动。进一步发现对于均能去除某一质因子集合的数,也只需要保留代价最小的m个。这样继续暴力去重,剩下数的数量不超过m·2m,并且同时我们可以求出每个数可以用于去除哪些集合,总集合数量是m·2m的。回到原dp中可以发现复杂度就变成了O(m2·3m)。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    #define ll long long
    #define N 1000010
    #define M 11
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    ll gcd(ll n,ll m){return m==0?n:gcd(m,n%m);}
    ll read()
    {
    	ll x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,cnt[M],t,LG2[1<<M];
    ll m,k,p[M],pw[M][100],tot[1<<M],f[M][1<<M];
    bool flag[N];
    struct data
    {
    	int v;ll x;
    	bool operator <(const data&a) const
    	{
    		return x<a.x;
    	}
    }a[N],b[N];
    vector<int> s[N];
    priority_queue<data> q[1<<M];
    bool cmp(const data&a,const data&b)
    {
    	return a.v<b.v;
    }
    signed main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("d.in","r",stdin);
    	freopen("d.out","w",stdout);
    #endif
    	n=read(),k=read();
    	for (int i=1;i<=n;i++) m=gcd(m,a[i].x=read());
    	for (int i=1;i<=n;i++) a[i].v=read();
    	for (ll i=2;i*i<=m;i++)
    	if (m%i==0)
    	{
    		p[t++]=i;
    		while (m%i==0) m/=i;
    	}
    	if (m>1) p[t++]=m;if (t==0) {cout<<0;return 0;}
    	for (int i=0;i<t;i++)
    	{
    		pw[i][0]=1;
    		for (int j=1;j<100;j++) pw[i][j]=pw[i][j-1]*p[i];
    	} 
    	sort(a+1,a+n+1);
    	int u=0;
    	for (int i=1;i<=n;i++)
    	{
    		int v=i;
    		while (a[v+1].x==a[i].x) v++;
    		sort(a+i,a+v+1,cmp);
    		for (int j=1;j<=min(t,v-i+1);j++)
    		b[++u]=a[i+j-1];
    		i=v;
    	}
    	swap(a,b);n=u;
    	for (int i=0;i<M;i++) LG2[1<<i]=i;
    	for (int j=1;j<(1<<t);j++)
    		for (int i=0;i<t;i++)
    		q[j].push((data){0,100000000000000ll});
    	for (int i=1;i<=n;i++)
    	{
    		tot[0]=1;
    		ll u=a[i].x;memset(cnt,0,sizeof(cnt));
    		for (int j=0;j<t;j++)
    		while (u%p[j]==0) cnt[j]++,u/=p[j];
    		for (int j=1;j<(1<<t);j++)
    		{
    			tot[j]=tot[j^(j&-j)]*pw[LG2[j&-j]][cnt[LG2[j&-j]]];
    			if (tot[j]<=k&&a[i].v<q[j].top().x) q[j].pop(),q[j].push((data){i,a[i].v});
    		}
    	}
    	for (int j=1;j<(1<<t);j++)
    	while (!q[j].empty())
    	{
    		data x=q[j].top();q[j].pop();
    		s[x.v].push_back(j);
    	}
    	memset(f,42,sizeof(f));f[0][0]=0;
    	for (int i=1;i<=n;i++)
    		for (int j=t-1;j>=0;j--)
    		{
    			for (int k=0;k<s[i].size();k++)
    			{
    				int x=s[i][k];
    				f[j+1][x]=min(f[j+1][x],f[j][0]+a[i].v);
    				for (int y=(1<<t)-1^x;y;y=y-1&((1<<t)-1^x))
    				f[j+1][x|y]=min(f[j+1][x|y],f[j][y]+a[i].v);
    			}
    		}
    	ll ans=1000000000000000ll;
    	for (int i=1;i<=t;i++)
    	if (f[i][(1<<t)-1]<ans) ans=min(ans,i*f[i][(1<<t)-1]);
    	if (ans>=1000000000000000ll) cout<<-1;
    	else cout<<ans;
    	return 0;
    	//NOTICE LONG LONG!!!!!
    }
    

      E感觉过于神仙。

  • 相关阅读:
    Go语言中new()和 make()的区别详解
    对于Linux内核tty设备的一点理解
    中国移动MySQL数据库优化最佳实践
    深入分析Linux自旋锁
    JAVA大数据项目+整理的Mysql数据库32条军规
    MySQL DBA面试全揭秘
    LINUX 内核基础
    子查询
    linuxprobe----LINUX 基础课程目录学习
    从事分布式系统,计算,hadoop
  • 原文地址:https://www.cnblogs.com/Gloid/p/10409630.html
Copyright © 2020-2023  润新知