ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
题目链接:https://codeforces.com/contest/1110
奇偶判断
有1到m 有n个区间点
使用不超过k个木板,覆盖所有点,要求木板最短
-------------------------------------------
对间隔排序,去掉间隔大的间隔
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
ll n,m,k,a[100005],b[100005];
int main(){
cin>>n>>m>>k;
fo(i,1,n)scanf("%d",&a[i]);
fo(i,1,n-1)b[i]=a[i+1]-a[i]-1; // 间隔
int ans = a[n]-a[1]+1;
sort(b+1,b+n);
for(int i=0; i<k-1 && n-1-i>0; i++){
ans -= b[n-1-i];
}
cout<<ans<<endl;
return 0;
}
给一堆数,这两种情况是合法序列[x,x,x],[x,x+1,x+2]
问最多有多少个这玩意
-------------------------------------------------
对于每个数 i, 他有[i,i,i]和 [i-1,i,i+1], [i,i+1,i+2]与下一个点 i+1有联系
所以 f[i][j][k] 表示 第i个数,状态t1[i-1,i,i+1]有j个,t2[i,i+1,i+2]有k个
t0 = [i-2,i-1,i]有L 个
f[i][t1][t2] = max(f[i-1][t0][t1] + L +(num[i]-j-k-l)/3, f[i][t1][t2])
由于 (num[i]-j-k-l)%3 只有3种结果,所以舍弃的结果数只有3种
所以 j,k,l 的枚举范围为0到2 即可
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int maxn = 1000005;
int n,m,a[maxn];
int f[maxn][3][3];
void solve(){
fo(i,1,m){
fo(j,0,2){
fo(k,0,2){
// 影响第i个点的横放状态有两个,为i-1个点的
// [i-2,i-1,i],[i-1,i,i+1]
fo(l,0,2){
if(a[i]<j+k+l)continue;
// 横放[i,i+1,i+2],加竖放
f[i][j][k] = max(f[i][j][k], f[i-1][l][j] + k + (a[i]-j-k-l)/3);
}
}
}
}
cout<<f[m][0][0];
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,n){
int x;scanf("%d",&x);
a[x]++;
}
solve();
return 0;
}
给定数 a ,找出一个数 0<=b gcd( 2^x-1 - b, b)
====> gcd(2^x-1, b) 因为 gcd(x+y,y) ==> gcd(x,y)
所以我们只要找到最大的能整除的就行
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
ll q,n;
void solve(){
ll x=1;
while(x<=n){
x<<=1;
}
x--;
if(x==n){
// gcd(2^x-1 ^ b, b) =====> gcd( 2^x-1 - b, b)
// ====> gcd(2^x-1, b) 因为 gcd(x+y,y) ==> gcd(x,y)
// 所以我们只要找到最大的能整除的就行
for(int i=2; i*i<=n; i++){
if(n%i==0){
printf("%lld\n",n/i);
return;
}
}
printf("%lld\n",1ll);
}else{
// b = 2^x-1 ^ a ====> a^b = 2^x-1
// a&b = 0
// gcd(a^b, a&b) = gcd(2^x-1, 0) = 2^x-1;
printf("%lld\n",x);
}
}
int main(){
scanf("%lld",&q);
while(q--){
scanf("%lld",&n);
solve();
}
return 0;
}
E题目:
给定数组c[],对于c[i]可改变为 c[i+1]+c[i-1]-c[i]
问数组c,能否变成数组s
-------------------------------------------------
差分数组 d[i] = c[i]-c[i-1],d[1] = c[1]
c'[i] = c[i-1] + c[i+1] -c[i]
改变之后,差分数组变为
d'[i] = c[i-1] + c[i+1] - c[i] - c[i-1] = c[i+1] - c[i] = d[i+1]
d'[i+1] = c[i+1] -(c[i-1] + c[i+1] - c[i])= c[i] - c[i-1] = d[i]
也就是改变c[i]之后,差分数组做了交换,其他不变
所以我们只要排序后,查看两个差分数组是否相同即可
即首项和之后的变化项都相同
---------------------------------------------------------
题外:
差分数组描述一组数组的变换关系,只要首项一样,其他变换关系一样,则说明完全一样
差分数组d的前缀和 f 为 原数组
如果要修该原数组a,可修改差分数组d,然后d的前缀和f,即为新的所求数组
f的前缀和sum即为修改后的a的前缀和
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n,a1[100005],a2[100005],d1[100005],d2[100005];
int main(){
scanf("%d",&n);
fo(i,1,n)scanf("%d",&a1[i]);
fo(i,1,n)scanf("%d",&a2[i]);
d1[1]=a1[1],d2[1]=a2[1];
fo(i,2,n)d1[i] = a1[i]-a1[i-1],d2[i] = a2[i]-a2[i-1];
sort(d1+2,d1+1+n);
sort(d2+2,d2+1+n);
fo(i,1,n){
if(d1[i]!=d2[i]){
puts("No");
return 0;
}
}
puts("Yes");
return 0;
}
用线段树维护,我不会