zoukankan      html  css  js  c++  java
  • CF922 CodeForces Round #461(Div.2)

    CF922 CodeForces Round #461(Div.2)

    这场比赛很晚呀
    果断滚去睡了
    现在来做一下

    A

    CF922 A

    翻译:

    一开始有一个初始版本的玩具
    每次有两种操作:
    放一个初始版本进去,额外得到一个初始版本和一个复制版本
    放一个复制版本进去,额外得到两个复制版本
    一开始有(1)个初始版本,是否能恰好得到(x)个复制版本和(y)个初始版本

    Solution

    傻逼题
    要特判一些特殊情况(没有(1A)...)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int x,y;
    int main()
    {
    	x=read();y=read();
    	if(y==0){puts("No");return 0;}
    	if(y==1&&x!=0){puts("No");return 0;}
    	x-=y-1;
    	if(x<0){puts("No");return 0;}
    	if(x&1){puts("No");return 0;}
    	puts("Yes");
    	return 0;
    }
    
    

    B

    CF992 B

    翻译:

    给定一个长度(n)
    回答有多少个边长都小于(n)
    并且边长的异或和为(0)的三角形

    Solution

    还是傻逼题
    看到(n<=2500)
    又有(xwedge ywedge z=0)
    所以(xwedge y=z)
    暴力枚举(x,y)判断(xwedge y)是否满足条件就好

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int ans=0;
    int main()
    {
    	int n=read();
    	for(int i=1;i<=n;++i)
    		for(int j=i;j<=n;++j)
    			if((i+j)>(i^j)&&(i<(i^j))&&(j<(i^j))&&((i^j)<=n))
    				++ans;
    	printf("%d
    ",ans);
    	return 0;
    }
    
    

    C

    CF992 C

    翻译:

    给定(n,k)(n,kleq 10^{18})
    回答(n mod i,iin [1,k])是否都不同

    Solution

    这题很有意思
    我们来观察一下:
    (n\%1=0)
    (n\%2=0,1)
    (n\%3=0,1,2)
    既然(n\%1=0)
    所以(n\%2=1)
    所以(n\%3=2)
    这样推下去,发现(n\%i=i-1)
    所以给(n)加上(1)
    它就能够被(k!)整除
    当然不用算(k!)是什么
    直接从(k)开始倒着枚举每一个数就好啦

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    ll n,k;
    int main()
    {
    	cin>>n>>k;
    	n++;
    	for(ll i=k;i;--i)
    		if(n%i){puts("No");return 0;}
    	puts("Yes");
    	return 0;
    }
    
    

    D

    CF992 D

    翻译:

    (n)个由(s,h)组成的串
    这些串可以按照任意顺序连接
    最大化(sh)子序列(不用连续)的数量

    Solution

    我好傻呀
    这题其实挺简单的
    记得原来做过一道题目叫做“数字积木”
    就是给你若干个数字串,让你以一定顺序拼在一起
    使得组成的数字最大

    我们假设顺序已经定好
    只能进行冒泡排序
    如果比较两个相邻位置的顺序?
    把两个串按照顺序分别接在一起,比较哪个放在前面更优

    这题是一样的
    对于只考虑两个相邻位置
    前面其他串和后面其他串产生的贡献是不变的
    变的只有这两个串组合在一起的贡献
    所以计算两个是正着放更优还是反着放更优就好啦

    upd:
    感谢高神提醒,观察如果比较两个串拼接顺序产生的贡献
    每个串自己内部的贡献也是一定的,
    所以只需要考虑不同的串的贡献
    就是前面串的(s)数量乘上后面的(h)数量
    等价于按照(s)数量与(h)数量的比值排序

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 120000
    int n;
    string t[MAX],S;
    ll ans,tot;
    int ss[MAX],hh[MAX],id[MAX],SS,HH;
    ll calc(string s)
    {
    	ll ret=0,tot=0;
    	for(int i=0,l=s.length();i<l;++i)
    		if(s[i]=='s')++tot;
    		else ret+=tot;
    	return ret;
    }
    bool cmp(string a,string b)
    {
    	return calc(a+b)>calc(b+a);
    }
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin>>n;
    	for(int i=1;i<=n;++i)cin>>t[i];
    	sort(&t[1],&t[n+1],cmp);
    	for(int i=1;i<=n;++i)S+=t[i];
    	cout<<calc(S)<<endl;
    	return 0;
    }
    
    

    E

    CF922 E

    翻译:

    一条直线上有(n)棵树
    每棵树上有(ci)只鸟
    在一棵树底下召唤一直鸟的魔法代价是(costi)
    没召唤一只鸟,魔法上限会增加(B)
    从一棵树走到另一棵树,会增加魔法(X)
    一开始的魔法和魔法上限都是(W)
    问最多能够召唤的鸟的个数

    Solution

    发现关于魔法值的量的范围都非常大
    但是鸟的个数很少
    所以考虑(dp)的时候就不压魔法值
    压鸟的只数
    (f[i][j])表示前(i)棵树上,已经召唤了(j)只鸟,剩余的最大魔力值
    转移应该很显然了
    此时每次的最大魔力值也都能够算出
    很高兴的(AC)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 1111
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int n;
    ll W,B,X;
    ll f[1010][10010];
    int c[MAX],v[MAX];
    ll s[MAX];
    int main()
    {
    	n=read();W=read();B=read();X=read();
    	for(int i=1;i<=n;++i)s[i]=s[i-1]+(c[i]=read());
    	for(int i=1;i<=n;++i)v[i]=read();
    	memset(f,-63,sizeof(f));
    	f[0][0]=W-X;
    	for(int i=1;i<=n;++i)
    	{
    		for(int j=0;j<=s[i-1];++j)
    		{
    			if(f[i-1][j]<-1e9)continue;
    			ll tm=f[i-1][j];
    			tm=min(W+j*B,tm+X);
    			for(int k=0;k<=c[i];++k)
    			{
    				if(tm<v[i]*k)break;
    				f[i][j+k]=max(f[i][j+k],tm-v[i]*k);
    			}
    		}
    	}
    	for(int i=s[n];i;--i)
    		if(f[n][i]>=0)
    		{
    			printf("%d
    ",i);
    			return 0;
    		}
    	puts("0");
    	return 0;
    }
    
    

    F

    CF922 F

    翻译:

    对于一个数集(I)
    (f(I))表示(I)((a,b))的对数
    满足(a<b,b\%a=0)
    找出一个所有元素都不大于(n)的集合(I)
    使得(f(I)=k)

    Solution

    如果所有数都被选了的话
    那么,每个数的贡献就是它的约数个数
    所以,对于约数个数可以求一个前缀和
    找到第一个(geq K)的位置就停下
    那么,现在相当于只要用这些数就可以组成(K)组了
    (默认从这个位置是(n)了)
    现在考虑怎么组合
    如果删掉一个数
    就要考虑他的倍数和约数的贡献的影响
    很麻烦,那么我们可以不可以抛开其中一个?
    当然可以,约数是一定存在的,
    但是倍数不一定,所以考虑一下没有倍数的数
    那就是(n/2~n)
    把这些数拿出来,按照约数个数排序
    如果这个数被删掉,就一定会减少他约数个数的贡献
    那么,从大到小排序之后,能删就删掉,这样就构造出了一组解
    (不会证明为什么这样子一定存在)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 300003
    int n,K;
    ll d[MAX];
    pair<int,int> c[MAX];
    int tot;
    bool vis[MAX];
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin>>n>>K;
    	for(int i=1;i<=n;++i)
    		for(int j=i<<1;j<=n;j+=i)++d[j];
    	for(int i=1;i<=n;++i)d[i]+=d[i-1];
    	if(K>d[n]){puts("No");return 0;}
    	for(int i=1;i<=n;++i)
    		if(d[i]>K){n=i;break;}
    	for(int i=n;i*2>n;--i)c[++tot]=make_pair(d[i]-d[i-1],i);
    	sort(&c[1],&c[tot+1]);
    	int ss=d[n]-K;
    	for(int i=tot;i;--i)if(ss>=c[i].first)ss-=c[i].first,vis[c[i].second]=true;
    	tot=0;
    	for(int i=1;i<=n;++i)if(!vis[i])++tot;
    	puts("Yes");
    	printf("%d
    ",tot);
    	for(int i=1;i<=n;++i)
    		if(!vis[i])printf("%d ",i);puts("");
    	return 0;
    }
    
    

    总结

    其实这几道题目难度感觉不是很大
    前面(5)题自己都能够做出来
    其中(E)题其实是原来一道很相似的题目
    但是想了很久才做出来,思维还是有点局限了
    (F)题构造题
    这种题目完全不擅长
    也不会做,看了别人的(AC)代码才写出来
    看来写完一场(CF)还是挺涨能力的

  • 相关阅读:
    外包、构件和黑盒抽象等杂想
    C++类型转换小记(一)——C++转换操作符
    大学(一)
    【答】如何获取一个【备份路径】的信息?
    橘色超漂亮滑动二级导航菜单
    CSS自适应宽度按钮
    我们忽略的IE特效——一些特殊效果
    MSSQL 游标示例
    [存]超酷JS拖拽翻页效果
    漂亮的表格
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8433057.html
Copyright © 2011-2022 走看看