传送门:CodeforcesRound510Div. 2
a+b>c
#include
using namespace std;
int a,b,c,ans;
int main(){
int i,j,k;
scanf("%d%d%d",&a,&b,&c);
if(a>b) swap(a,b);
if(a>c) swap(a,c);
if(b>c) swap(b,c);
if(a+b>c) printf("0");
else printf("%d",abs(c+1-a-b));
}
x ≤ a x\leq a x≤a,要使 x + x x o r a = a x+x\ xor \ a =a x+x xor a=a, x x x & a = x a=x a=x即 x x x为 a a a的二进制子集时显然成立。
尝试证明 x x x & a ≠ x a\neq x a̸=x时 x + x x o r a ≠ a x+x\ xor \ a\neq a x+x xor a̸=a:
设 x x x的某二进制位 i i i为1,而 a a a的该二进制为 0 0 0,必然一串连续的 i i i相加要进位到 a a a上为1的位置 j ( j > i ) j(j> i) j(j>i)才行(同时需要保证 x + x x o r a x+x\ xor \ a x+x xor a的二进制位 j j j为0),而 x x x的二进制位 j j j为0, x x o r a x\ xor \ a x xor a的二进制为1,矛盾,所以不成立。
#include
using namespace std;
int t,a,ans,sum;
int main(){
int i,j,k;
scanf("%d",&t);
for(;t;--t){
scanf("%d",&a);
ans=1;
for(i=0;(1LL<>i)&1) ans<<=1;
}
printf("%d\n",ans);
}
}
这题坑了我好久。。。
实际上只需要排个序:对于每组相同的字母(个数为 k k k),其贡献最多为 k ( k + 1 ) 2 \dfrac{k(k+1)}{2} 2k(k+1),排序之后就能达到最优。
#include
using namespace std;
int n;char s[100005];
int main(){
scanf("%d%s",&n,s);sort(s,s+n);printf("%s",s);
return 0;
}
→_→考试的时候没有想到,就乱搞了一个方法:
把每个字母按出现次数排序,每次优先取比它出现次数多一的字母来组成形如 a b a b a . . . b a ababa...ba ababa...ba的串,没有比它出现次数多一的字母时就直接取自己组成 a a a a . . . a aaaa...a aaaa...a的串。(其实本质上和排序是一样的)
#include
using namespace std;
const int N=1e5+100;
int n,oc[27],sx[27],sum,ban[27];
int q[27],cnt,pre[26][N],st[N],nxt[N];
int a[N],b[N],ca,cb,mx[N];
char s[N];
inline bool cmp(const int&A,const int&B)
{return oc[A]
若一个位置 ( i , j ) (i,j) (i,j)可达,从起点 ( r , c ) (r,c) (r,c)至少需要左移 L L L,右移 R R R到达,则存在等式:
c + R − L = j → R − L = j − c c+R-L=j\to R-L=j-c c+R−L=j→R−L=j−c
得到 R R R的同时也就得到了 L L L。
所以选择其中一个作为距离01dfs即可。
#include
using namespace std;
const int N=2e3+10,M=4e6+10;
int n,m,la,lb,st,dis[M],ban[M],cg,ans;
char s[N];
int dx[6]={-1,1,0,0};
int dy[6]={0,0,-1,1};
int v[6]={0,0,1,0};
dequeQ;
int main(){
int i,j,x,y,z,ix,iy,iz,lim,ori;
scanf("%d%d",&n,&m);
scanf("%d%d",&x,&y);
st=(x-1)*m+y-1;ori=y-1;
scanf("%d%d",&la,&lb);
lim=0;
for(i=0;i=n || y<0 || y>=m || ban[z] || dis[z]<=dis[iz]+v[i]) continue;
dis[z]=dis[iz]+v[i];
i==2? Q.push_back(z):Q.push_front(z);
}
}
x=0;
for(i=0;i
一个简单的二分。
关键在于看出数据范围的提示:
1 ≤ n ≤ 30 , 0 ≤ x , y ≤ 1 0 9 1\leq n\leq30,0\leq x,y\leq 10^9 1≤n≤30,0≤x,y≤109。
刚好一个 L o g Log Log,于是初始 l = 0 , r = 1 0 9 l=0,r=10^9 l=0,r=109每次放在 m i d mid mid,根据颜色收敛即可。
#include
using namespace std;
int n,x,y,mid,l,r=1e9,ori;
char s[10];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
printf("1 %d\n",mid);
cin>>s;
if(i==1) ori=s[0];
if(s[0]==ori) l=mid;
else r=mid;
mid=(l+r)>>1;
}
printf("0 %d 2 %d\n",l,r);
return 0;
}
乍一看觉得可以 O ( n ) O(\sqrt n) O(n)做,写到一半才发现无论选择枚举人数还是轮数
都不能保证复杂度。
看了 e d i t o r i a l editorial editorial发现这其实是一道分类讨论,可以两种方法结合来做,取 m i n ( n 2 , k n ) min(n^2,\dfrac kn) min(n2,nk)。
设总糖数为 t o t tot tot。这里假设均满足最后一个人取满的情况(若其为 s w e e t t o o t h sweet tooth sweettooth则能够取2个,否则取1个)
n 2 n^2 n2的做法:设最后多进行一轮的人数为 x x x,其余人数为 y ( y = n − x ) y(y=n-x) y(y=n−x), x x x中 s w e e t t o o t h sweet\ tooth sweet tooth个数为 a a a, y y y中 s w e e t t o o t h sweet\ tooth sweet tooth个数为 b b b。
直接枚举判断即可。
k n \dfrac kn nk的做法:枚举场数 t ( t ≤ k n ) t(t\leq \dfrac kn) t(t≤nk),存在等式:
( x + a ) × ( t + 1 ) + ( y + b ) × t = t o t (x+a)\times (t+1)+(y+b)\times t=tot (x+a)×(t+1)+(y+b)×t=tot
也即:
a × ( t + 1 ) + b × t = c o n s t , c o n s t = t o t − x × ( t + 1 ) − y × t a\times (t+1) + b\times t = const,const =tot-x\times (t+1)-y\times t a×(t+1)+b×t=const,const=tot−x×(t+1)−y×t
0 ≤ a ≤ x , 0 ≤ b ≤ y 0\leq a\leq x,0\leq b\leq y 0≤a≤x,0≤b≤y
随便求出一组 a 0 , b 0 a_0,b_0 a0,b0(可以不满足条件),能够发现对于任意整数 z z z,
存在 a = a 0 − t z , b = b 0 + ( t + 1 ) z a=a_0-tz,b=b_0+(t+1)z a=a0−tz,b=b0+(t+1)z使得等式成立,所以所有合法的答案可以用如下形式表示:
a = a 0 − t z , b = b 0 + ( t + 1 ) z a=a_0-tz,b=b_0+(t+1)z a=a0−tz,b=b0+(t+1)z
m a x ( ⌈ a 0 − x t ⌉ , ⌈ − b 0 t + 1 ⌉ ) ≤ z ≤ m i n ( ⌊ a 0 t ⌋ , ⌊ y − b 0 t + 1 ⌋ ) max(\lceil \dfrac{a_0-x}{t}\rceil,\lceil\dfrac{-b_0}{t+1}\rceil)\leq z \leq min(\lfloor\dfrac{a_0}{t}\rfloor,\lfloor \dfrac{y-b_0}{t+1}\rfloor) max(⌈ta0−x⌉,⌈t+1−b0⌉)≤z≤min(⌊ta0⌋,⌊t+1y−b0⌋)
答案即求 m a x ( a + b ) max(a+b) max(a+b),而由 a × ( t + 1 ) + b × t = c o n s t a\times (t+1) + b\times t = const a×(t+1)+b×t=const,得到:
a + b = c o n s t − a t a+b=\dfrac{const-a}{t} a+b=tconst−a,代入 a 0 a_0 a0,得到: a + b = c o n s t − a 0 t + z a+b=\dfrac{const-a_0}{t}+z a+b=tconst−a0+z
直接 z m a x z_{max} zmax更新答案即可。
需要注意一些细节上的东西:
存在一种特殊的情况:最后一个人是 s w e e t t o o t h sweet tooth sweettooth但是仅剩一颗糖,此时实际上的总糖数应为 t o t + 1 tot+1 tot+1。
对于每种枚举都要考虑这种特殊情况,但注意必须要保证此时枚举到的 a ≥ 1 a\geq 1 a≥1。
#include
using namespace std;
typedef long long ll;
ll n,l,r,tot,x,y,d,rd,ans=-1;
//上下取整
inline ll gt(ll x,ll y)
{
if(x==0) return 0;
return x>0?((x-1)/y+1):(x/y);
}
inline ll ft(ll x,ll y)
{
if(x==0) return 0;
return x>0?(x/y):((x+1)/y-1);
}
int main(){
ll i,j,res,sum;
scanf("%I64d%I64d%I64d%I64d",&n,&l,&r,&tot);
d=l<=r?(r-l+1):(r+n-l+1);rd=n-d;
if(n<=5000){
for(i=0;i<=d;++i)
for(j=0;j<=rd;++j){
sum=n+i+j;res=(tot-1)%sum+1;
if(res==d+i) ans=max(ans,i+j);
else if(i && res==d+i-1) ans=max(ans,i+j);
}
}else{
ll lim=tot/n,dd=d<<1,mn,mx;
if(tot+1>=d && tot+1<=dd) ans=max(ans,tot+1-d+rd);
else if(tot>=d && tot<=dd) ans=max(ans,tot-d+rd);
for(i=1;i<=lim;++i){
res=tot-(i+1)*d-i*rd;
if(res>=0){
x=res%i;y=res/i-x;
mx=min(ft(x,i),ft(rd-y,i+1));
mn=max(gt(x-d,i),gt(-y,i+1));
if(mn<=mx) ans=max(ans,(res-x)/i+mx);
}
res++;
if(res>=0){
x=res%i;y=res/i-x;
mx=min(ft(x-1,i),ft(rd-y,i+1));
mn=max(gt(x-d,i),gt(-y,i+1));
if(mn<=mx) ans=max(ans,(res-x)/i+mx);
}
}
}
printf("%I64d",ans);
return 0;
}
这场考试还是比较有思维难度E,F