暑假集训笔记

Problem - D - Codeforces

这题比赛的时候用dfs打了个全排列,有点猜的成分..然后就猜对了

在比赛过程中没有验证其正确性,今天看了题解,发现确实证明的很好!!

1..其中n只能放在第一位:

用反证法证明 b(i+1)=(bi+n)%n=bi,所以n只能放在第一位

2.n为奇数时候没有构造方案

1+2+3...+n=(n+1)*n/2,模n答案为0,又第一位只能放n答案也为0,故不行

3.当n为偶数的时候,发现构造

1 ,n   ,2 ,n-1  ,3,n-2是一个好的构造方法..不会证明比赛时候看样例猜的

#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;
		scanf("%lld",&n);
		
		if(n==1){
			printf("1\n");
			continue;
		}
		if(n==2){
			printf("2 1\n");
			continue;
		}
		if(n&1){
			printf("-1\n");
			continue;
		}
		
		int left=1;
		int right=n;
		int pre=0;
		for(int i=1;i<=n;i++){
			int now=(i+1)/2;
			
			if(i&1){
				printf("%d ",now*n+left-1-pre);
				pre=now*n+left-1;
				left++;
			}else{
				printf("%d ",now*n+right-1-pre);
				pre=now*n+right-1;
				right--;
			}
		}
		printf("\n");
		
	}


	return 0;
}

 

Problem - E - Codeforces

挺可惜的一道题目...

比赛时候差一点就出了(???差一点??)

其实我有个地方考虑不周...

看样例知道n为奇数时候一定无解

当n为偶数时,我们统计每一个字母出现的次数,如果出现次数>n/2,一定无解,因为一定有这个字母的配对!!!

否则我们就统计每个配对的种类和个数

因为每个种类数和另外种类的交换,花费1但是同时减去2个配对,所以这个是最优的

,如果只剩下一种了,那么每个配对花费1(比赛时我还考虑是否交换之后是否一定不出现矛盾

比如abaa,aa和ab交换后出现矛盾)事实上是不会的,因为出现矛盾的情况一定是某个字母出现的次数>n/2的情况了

比赛过程中有个地方没有考虑情况:

每个种类只能和其他种类配对,但是不一定只能和一种配对(这不是最优的)

比如 aa  aa  bb  bb cc  cc,最小花费为3(aa和cc   aa和bb ,bb和cc)

但我考虑的最小花费为4(aa和bb,aa和bb,然后cc在单独交换)

比赛过程中我写的....

for(auto it =mp.begin();it!=mp.end();it++){
			if(it->second!=0){
				for(auto k=mp.begin();k!=mp.end();k++){
					if(k->first!=it->first&&k->second!=0){
						if(it->second>k->second){
							it->second= it->second- k->second;
							ans=ans+k->second;
							k->second=0;
							
						}else{
							ans=ans+it->second;
							k->second=k->second-it->second;
							it->second=0;
							break;
						}
					}
				}
			}
		}
		
		
		for(auto it=mp.begin();it!=mp.end();it++){
			if(it->second!=0)ans=ans+it->second;
		}

其实我们只需统计出现最多配对种类cnt,和总的配对数目sum

如果2*cnt>=sum,答案为cnt

否则答案为(sum+1)/2(如果sum为奇数的话,需要多加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 t;
int main(){
	scanf("%d",&t);
	
	while(t--){
		
		int n;
		
		scanf("%d",&n);
		
		string s;
		
		cin>>s;
		
		if(n&1){
			printf("-1\n");
			continue;
		}
		
		int maxn=0;
		map mp;
		s=" "+s;
		
		for(int i=1;i<=n;i++){			
			mp[s[i]]++;
			maxn=max(maxn,mp[s[i]]);		
		}
		
		if(maxn>n/2){
			printf("-1\n");
			continue;
		}
		
		ll ans=0;
		
		mp.clear();
		ll cnt=0; 
		maxn=0;
		for(int i=1,j=n;i<=n/2;i++,j--){
			if(s[i]==s[j]){
				mp[s[i]]++;
				maxn=max(maxn,mp[s[i]]);
				cnt++;		
			}
		}
		
		if(2*maxn>=cnt){
			printf("%d\n",maxn); 
		} else{
			printf("%d\n",(cnt+1)/2);
		}
	
	}

	return 0;
}

 

Problem - C - Codeforces

今天晚上vp做的,没思路啊!!

刚刚补完这题..居然是dfs...

初始化:

字符串s统计所有字符

	cin>>n>>k;
		for(int i=0;i<30;i++)vis[i]=0;
		cin>>a>>b;
		setq;
		
		for(int i=0;i

主要看下dfs吧,

pos为到了第几个位置,cnt为一共标记了几个字母

void dfs(int pos,int cnt){
	
	if(pos==s.size()){
		if(cnt==k)ans=max(ans,calc());
		return ;
	}
	dfs(pos+1,cnt);
	vis[s[pos]-97]=1;
	dfs(pos+1,cnt+1);
	vis[s[pos]-97]=0;
	
}

计算

我们发现长度为x的字串对答案的贡献为(x+1)*x/2

	ll ans=0;
	ll now=0;
	for(int i=0;i

其实比赛过程中我就注意到了可以枚举k的字母的选取,我想暴力取的...

种类数为C26   k,最大的数好像才84,987,760...不会超时啊!!!

比赛时候没有算清楚啊!!!

回去休息了..

明天见

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