A. Magical Sticks
给你n个木棍,可以任意拼接,问你最多能有多少个相同长度的,那肯定是1和n拼n+1,2和n-1拼n+1,以此类推
int T,n;
int main()
{
cin>>T;
while(T--)
{
cin>>n;
//a+b=c
//1+n=n+1
//2+n-1=n+1
cout<<(n+1)/2<<"\n";
}
return 0;
}
B. Magical Calendar
找不相等的排列
由于需要联通,所以当n>k的时候,肯定是联通的,随便摆,方案数是k,当n=k的时候,因为需要联通,只能在同一行,所以方案数是1,当n<k的时候,因为需要联通,同样只能在同一行,而既然在同一行了,长度又肯定是n,和n=k的时候排列重复了,都不用考虑了,所以最后的总方案数就是n>k的时候,k的总和,再加上n=k的时候的1
ll T,n,r;
int main()
{
cin>>T;
while(T--)
{
long long sum=0;
cin>>n>>r;
// rep(i,1,r+1)
// for(ll i=1;i<=r;i++)
// {
// if(n>=i+1)
// sum+=i;
// else
// {
// sum+=i+1-n;
// break;
// }
// }
//1~n-1
if(r>=n-1)
sum+=n*(n-1)/2;
else
sum+=r*(r+1)/2;
if(r>=n)
sum+=1;
cout<<sum<<"\n";
}
return 0;
//n==k 1
//n=k+1 k
//n>k+1 k
//n=k-i i+1
//n=1 k
//n=0 0
//k+1-n k->maxn
}
C. A Cookie for You
2类客人,对物品取舍不同,第一类人假如v>c,优先选v的,第二类人却选c的,所以第二类人肯定比第一类人危险多了,毕竟他每次是优先选少的,万一那一堆是0就出事了
所以最好的方案肯定是先第一类人,把a,b里多的拿走,直到a=b,然后先第一类人,再第二类人,这样每次结束后a都保持等于b,然后分析啥时候n和m消耗完,没了,记得开longlong,一开始是int,wa 3了
ll T,a,b,n,m;
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>a>>b>>n>>m;
if(a+b<n+m)
{
cout<<"No\n";
continue;
}
//u==c 第二类 u-- then 第一类 c-- 变回去了
ll asd=abs(a-b);
asd=min(asd,n);
n-=asd;
if(a>b)
a-=asd;
else
b-=asd;
if(n==0)
{
if(m<=min(a,b))
{
cout<<"Yes\n";
}
else
cout<<"No\n";
}
else
{//a==b
// int qwe=abs(n-m);
ll qwe=min(n,m);
a=b=a-qwe;
n-=qwe,m-=qwe;
if(n==0)
{
if(m<=a)
cout<<"Yes\n";
else
cout<<"No\n";
}
else
{
if(n<=a+b)
cout<<"Yes\n";
else
cout<<"No\n";
}
}
}
return 0;
}
D. Grid-00100
一开始还以为要使f(A)尽量大,然后才发现是尽量小。。。
然后口胡了一个解法,就是每次斜着填格子,直到k=0,然后,然后就过了。。。
int T,a[400][400];
int n,k;
int main()
{
cin>>T;
while(T--)
{
ms(a);
int cnt=1;
cin>>n>>k;
int i=1,j=1;
while(k--)
{
a[i++][j++]=1;
if(j>n)
j=1;
if(i==n+1)
{
i=1;
j=++cnt;
}
//1 1 2 2 1 2
}
int lmax=0,lmin=inf,cmax=0,cmin=inf;
rep(i,1,n+1)
{
int sum=0,num=0;
rep(j,1,n+1)
{
sum+=a[i][j];
num+=a[j][i];
}
lmax=max(lmax,sum);
lmin=min(lmin,sum);
cmax=max(cmax,num);
cmin=min(cmin,num);
}
cout<<(lmax-lmin)*(lmax-lmin)+(cmax-cmin)*(cmax-cmin);
cout<<"\n";
rep(i,1,n+1)
{
rep(j,1,n+1)
cout<<a[i][j];
cout<<"\n";
}
}
return 0;
}
E1. Asterism (Easy Version)
E2. Asterism (Hard Version)
题意太难懂了。。。。读了10分钟我才发现一开始理解错了
大概意思就是枚举x的初始值,使得最后排序方案不得被p整除
那就先确定肯定被p整除的情况,首先肯定是没有方案的时候,设a[i]中最大值为maxx,那也就是n<maxx-n+1,这样无论怎么排序,最大值都无法取到,所以假如不被p整除,n至少得大于等于maxx-n+1,而我们又知道n>=p,所以假如n>=maxx,就是可以全排列了,方案数是
n
!
n!
n!的时候,
n
!
n!
n!必然被p整除,所以n必然<maxx
所以有可能不被p整除时,n的范围在[maxx-n+1,maxx)之间
E1范围小,可以直接枚举,但E2范围大如何解决呢?
我们可以这么分析,假如a[i]放在i位置上,那他必然可以放在i+1,i+2,i+…,n位置上,因为后面的时候,x在不断+1,假如在i位置都可以保证x>=a[i],那么在后面更可以保证,所以我们可以预处理每个值有多少个a[i]可以小于等于此值,先把a数组sort一下,然后直接二分查找,设sum[i]为小于等于i的a[i]的数量,统计,然后就可以计算了,大概是这个式子
∏
i
=
x
x
+
n
−
1
x
−
(
i
−
s
u
m
[
i
]
)
\prod_{i=x}^{x+n-1}{x-(i-sum[i])}
∏i=xx+n−1x−(i−sum[i]),i从x一直到n-1,一直叠乘,所以中间假如每次出现了能被p整除的,就可以直接break了,去找下一次的x了,而我们又发现
i
−
s
u
m
[
i
]
i-sum[i]
i−sum[i]其实是固定的,所以我们而每次直接查
x
x
x和
i
−
s
u
m
[
i
]
i-sum[i]
i−sum[i]是否关于p同余就行,所以我们直接把num[i]设为储存
i
−
s
u
m
[
i
]
i-sum[i]
i−sum[i]对p的余数的数量,每次判断x的时候,直接查询相应的num[x%p]是否为0,为0的话意味着没有一个
i
−
s
u
m
[
i
]
i-sum[i]
i−sum[i]跟此次的x同余,那就可行的,扔进vector数组,同时不管可行与否,因为x已经判断完毕,应该删除x的贡献,同时为了x+1的检验,加入x+n的贡献,做完了
vector<int> v1;
int n,p;
int a[maxn];
int num[maxn];
int main()
{
cin>>n>>p;
rep(i,1,n+1)
cin>>a[i];
sort(a+1,a+n+1);
// rep(i,1,n+1)
// {
// s[i]=s[i-1]+a[i];
// }
rep(i,a[n]-n+1,a[n]+1)
{
// int asd=lower_bound(a+1,a+n+1,i)-a-1;
int asd=upper_bound(a+1,a+n+1,i)-a-1;
num[((i-asd)%p+p)%p]++;
// if(num[i%p]==0)
// v1.push_back(i);
// num[asd]
}
rep(i,a[n]-n+1,a[n]+1)
{
if(num[(i%p+p)%p]==0)
v1.push_back(i);
int asd=upper_bound(a+1,a+n+1,i)-a-1;
int qwe=upper_bound(a+1,a+n+1,i+n)-a-1;
num[((i-asd)%p+p)%p]--;
num[((i-qwe+n)%p+p)%p]++;
}
cout<<v1.size()<<"\n";
for(int i:v1)
{
cout<<i<<" ";
}
cout<<"\n";
return 0;
}
//赢了永久+1
//全赢
//1. x>= maxn a[i] n! %p==0
//2. x<minn a[i] 0
//3. x>=maxn-n+1 maxn放最后一位
//4 .x< maxn-n+1 无解 %p==0
//maxn-n+1 ~ maxn
//x>=a[i]-i+1
// x ~ x+n-1
// min max
//ti-(0~n-1)
//x-(i-ti) x x+n-1
F. Raging Thunder
2800的题呀,emmm,要不逃?
n个传送带,n+1个洞
有q次翻转操作
问你哪个洞里球会最多,输出这个数量
很标准的线段树的啦,直接建2个树,一个原本的,一个默认全部翻转,每次翻转[l,r]的时候就交换这2个树这2个区域的值
想法很简单,但是实际操作嘛,emmmm,就很繁琐了
先留着吧,过2天再补