暑假集训记录8.2

今天感觉效率还行,就是太想睡觉了....这个....晚上不熬夜就行了..但是但是!!!

我这个坏毛病改不了啊。。。哭..

Problem - 1396A - Codeforces

一道1600分的题,没看题解自己写出来了...但就是wa了好几发,看了样例...

先说说我的思路极其的麻烦啊!!

一开始我就手玩一下,好像看出了规律了

选取1和n-1这一区间然后对对面操作都可以使他们变成n的倍数

但是...

我推着推着出现了:(a+kb)%c==0这个式子,其中b=n-1,c=n.,a=a[i]..

这怎么做..我想了好久,感觉枚举不太行啊...

然后又想了好久,期间还问了我队友。最后我一移项发现原式等价于a=kb+cp,其中b和c是相邻的,一定互质而且一定有解

然后我又去搜搜了扩展欧几里得

算法学习笔记(8):拓展欧几里得 - 知乎

但是我答案一直不对..
原来扩展欧几里得解的是ax+by=gcd(a,b)

要得到ax‘+by‘=c只需使x'=c/gcd(a,b)*x,y=c/gcd(a,b)*y即可

其中还有好多细节问题..忘记开ll,忘记1的情况...

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include 
#include 
using namespace std;
typedef  long  long ll ;
typedef  unsigned long  long ull ;
#define pii pair
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
int exgcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x); //这里交换了x和y
    y -= (a / b) * x;
    return d;
}
ll t;
ll a[1000005];
int main(){
	scanf("%lld",&t);
	for(int i=1;i<=t;i++)scanf("%lld",&a[i]);
	
	if(t==1){
		printf("1 1\n");
		if(a[1]==t){
		printf("%lld\n",t);
		a[1]=2*t;
		}else{
		printf("%lld\n",t-a[1]);
		a[1]=t;
		}	
		printf("1 1\n");
		if(a[1]==t){
		printf("%lld\n",t);
		a[1]=2*t;
		}else{
		printf("%lld\n",t-a[1]);
		a[1]=t;
		}
		
		printf("1 1\n");
		printf("%lld\n",-a[1]);
		return 0;
	}
	
	
	
	printf("%lld %lld\n",t,t);
	if(a[t]==t){
		printf("%lld\n",t);
		a[t]=2*t;
	}else{
		printf("%lld\n",t-a[t]);
		a[t]=t;
	}
	
	printf("1 %lld\n",t-1);
	for(int i=1;i<=t-1;i++){
		ll x,y;
		exgcd(t-1,t,x,y);
		printf("%lld ",-x*a[i]*(t-1)); 
		a[i]=a[i]-x*a[i]*(t-1);
	}
	
	printf("\n");
	printf("1 %d\n",t);
	for(int i=1;i<=t;i++){
		printf("%lld ",-a[i]);
	}
	
	
	

	return 0;
}

 

看了题解之后才知道我的代码是多么的麻烦啊...

我们第一次操作将1变为0

第二次操作,对前n个数(除了第一个数+0)其他都减去n*a[i]

第三次操作对后n-1个数加上(n-1)*a[i]

Problem - 1426D - Codeforces

这题也没出来...可能是自己没有好好想吧...

感觉真需要认真的想一想啊

想了之后发现真简单..

设L和R的区间和为0

设a为前缀和

等价a[R]-a[L-1]=0

即a[R]=a[L-1]

所以我们用一个set来存即可,如果有set就清空,并且前缀和从新计算.

然后将一个特别大的数插在i之前,花费+1

注意0要提前插入set,防止出现5 -5 这种情况

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include 
#include 
using namespace std;
typedef  long  long ll ;
typedef  unsigned long  long ull ;
#define pii pair
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
int n;
int main(){
	scanf("%d",&n);
	ll ans=0;
	sets;
	s.insert(0);
	ll now,x;
	now=0;
	for(int i=1;i<=n;i++){
		cin>>x;
		now=now+x;
		if(s.count(now)){
			s.clear();
			s.insert(0);
			ans++;
			now=x;	
		}
		s.insert(now);
		
	} 
		
	cout<

Problem - 1497C2 - Codeforces

这题想了好久没出来...

我一直在往1和偶数那里靠..但是...最后也没出

忘记了偶数/2之后可能是奇数的情况了

确实这题还有个简单版本,但是k=3,我感觉如果先做简单版本的话,思路可能会更好点

简单版本:

n如果为奇数,分为n/2,n/2,1三个数

如果n为偶数且不为4的倍数,分为n/2-1,n/2-1,2

如果n为4的倍数,分为n/2,n/4,n/4,

奇数的情况很好理解,为啥偶数要分是否为4的倍数呢,只考虑偶数不行吗?

因为如果n/2-1必须是偶数才能满足条件:n/2即奇数,所以n不是4的倍数

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include 
#include 
using namespace std;
typedef  long  long ll ;
typedef  unsigned long  long ull ;
#define pii pair
const int inf = 0x3f3f3f3f;//106110956
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
int t;
int main(){
	scanf("%d",&t);
	while(t--){
		ll n,k;
		cin>>n>>k;
		
		for(int i=1;i<=k-3;i++){
			printf("1 ");
		}
		
		int now=n-k+3;
		if(now&1){
			printf("%lld %lld %lld\n",now/2,now/2,1);
			continue;
		}
		if(now%2==0&&now%4!=0){
			printf("%lld %lld %lld\n",now/2-1,now/2-1,2);
			continue;
		}	
		printf("%lld %lld %lld\n",now/2,now/4,now/4);
	}


	return 0;
}

 

今天还学了倍增..感觉还是很好理解的..

[NOIP2013 提高组] 火柴排队 - 洛谷

这题归并排序.

虽然是蓝题但是很模板,就有一点非常难想

我们存一个数组c[i];
 c[B[i]编号]=A[i]编号;为什么这么做?
 数据说话:
 A:2 3 1 4->1 2 3 4对应原编号为:3 1 2 4
 B:3 2 1 4->1 2 3 4对应原编号为:3 2 1 4
 c[B[1]编号]=c[3]=a[1]编号=3
 c[B[2]编号]=c[2]=a[2]编号=1
 c[B[3]编号]=c[1]=a[3]编号=2
 c[B[4]编号]=c[4]=a[4]编号=4
 于是c[1]=2 c[2]=1 c[3]=3 c[4]=4
 逆序对数=1,交换一次,结束;

为什么这样呢?这就是查看排队后,之前与它同行的数是否现在还同行,否则就会产生逆序对

你可能感兴趣的:(笔记,算法)