复盘7.8训练

Posted karshey

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了复盘7.8训练相关的知识,希望对你有一定的参考价值。

手感奇差,WA了贼多发的一次训练。

A-Pretty Permutations

原题
简单思维题,观察可得:偶数两两交换,奇数最后一个跟交换过的倒数第二个再交换可得。
注意
不要被样例迷惑了,不是要顺逆时针的旋转!

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[105];
int main()
{
	int t;cin>>t;
	while(t--)
	{
		memset(a,0,sizeof(a));
		int n;cin>>n;
		for(int i=1;i<=n;i++)
		{
			a[i]=i;
		}		
		if(n%2==0) //偶数
		{
			for(int i=1;i<=n;i=i+2)
			{
				swap(a[i],a[i+1]);
			}
		} 
		else //奇数 
		{
			for(int i=1;i<n;i=i+2)
			{
				swap(a[i],a[i+1]);
			}			
			swap(a[n],a[n-1]);
		}
		for(int i=1;i<=n;i++)
		{
			cout<<a[i]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

B - Pleasant Pairs

原题

要求存在的i+j==a[i]*a[j]的个数。

注意:直接双层循环肯定会T。所以要想办法剪枝。(因为其实符合题意的并不多,如果每一个都判断一次就会复杂度很高,所以要把先符合要求的筛选出来再判断)

a[i]*a[j]=i+j;
由于a[j]最小为1,则有:n>=j>=a[i]-i;
由题意可得,j每次是a[i]倍增加的(a[i]*a[j])
故有:
for(int j=a[i]-i;j<=n;j=j+a[i])

最后注意j要大于i判断一下,开ll即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=1e5+10;
ll a[N];
int main()
{
	int t;cin>>t;
	while(t--)
	{
		memset(a,0,sizeof(a));
		int n;cin>>n;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
		}
		ll ans=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=a[i]-i;j<=n;j=j+a[i])
			{
				if(j<=i) continue;
				if(a[i]*a[j]==i+j) ans++;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

C - Colorful Transceivers

原题
超级无敌大水题了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
// ab bc直接 ac 间接 
//ac 可通 yes 
int main()
{
	int a,b,c,d;cin>>a>>b>>c>>d;
	if(abs(a-c)<=d) cout<<"Yes"<<endl;
	else
	{
		if(abs(a-b)<=d&&abs(b-c)<=d) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}
	
	return 0;
}

D - Exponential

原题
注意数据范围小,才1000,这妥妥的可以打表!
做的时候没想到,结果直接T了贼多发

打表过程见代码。打完表还WA,竟是因为…忘记可以等于了…
注意,不用去重

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int cmp(int a,int b)
{
	return a>b;
 } 
int main()
{
	int x;cin>>x;
	if(x<=3) {
		cout<<1;return 0;
	}
	//打表:2次方 
	int p=0,a[1005];
	for(int i=2;i<=31;i++) //32^2>1000
	{
		a[p++]=pow(i,2);
	} 
	
	//3
	for(int i=2;i<=10;i++) //10^3==1000
	{
		a[p++]=pow(i,3);
	}
	
	//5
	for(int i=2;i<=3;i++) //4^5>1000
	{
		a[p++]=pow(i,5);
	}
	
	//7
	a[p++]=pow(2,7);   //3^7>1000
	
	//2^11>1000 到11打表结束 
	
	sort(a,a+p);
	
	//
//	for(int i=0;i<p;i++)
//	{
//		cout<<a[i]<<endl;				
//	}	
	//	
		
	for(int i=p-1;i>=0;i--)
	{
		if(a[i]<=x) 
		{
			cout<<a[i];
			return 0;
		}
	}
	return 0;
}

E- A - B = C

原题
大意:输入L,R,在LR中有多少ABC在LR范围内满足A-B=C;观察可得,等差数列
看样例,有提示。
这题真的见识到了cin和cout会T,必须用printf和scanf。
ps:第一次WA的时候判断了输入的LR相同等等之类的情况,其实可以被这里idx<1的判断一言以蔽之。可能是我多加了判断但判断的不全面。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
	int t;cin>>t;
	while(t--)
	{
		int a,b;scanf("%d%d",&a,&b);		
		ll idx=(b-2*a+1);
		ll ans=0;
		if(idx<1) 
		{
			printf("0\\n");
		}
		else
		{
			ans=(1+idx)*idx;
			ans/=2;
			printf("%lld\\n",ans);
		}		
	}
	return 0;
}

F - K-th Substring

原题
求出第k个字典序最小的字串。

注意:k<=5的,如果所有字串都求出来会T,也要有剪枝思想。所以循环的时候内层循环1~5即可。
STL的set可以自动排序和去重,用它做容器。(第一次A的时候竟然手动排序和去重,傻了)
取字符子串的用substr,当然也可以自己加。

两个循环:外层是0-len-1,内层是1-5的闭区间。注意判断是否超出长度。

for(int i=0;i<=len-1;i++)		
	for(int j=1;j<=5;j++)
		{		
			if(i+j-1>=len) continue;
			s.insert(a.substr(i,j));
		}	

见代码:
set版:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
	string a;cin>>a;
	int k;cin>>k;
	int len=a.size();	
	set<string>s;
	for(int i=0;i<=len-1;i++)
	{		
		for(int j=1;j<=5;j++)
		{		
			if(i+j-1>=len) continue;
			s.insert(a.substr(i,j));
		}
	}
	set<string>::iterator iter;
	int temp=1;
	for(iter=s.begin();iter!=s.end();iter++)
	{				
		if(temp==k){cout<<*iter<<endl;return 0;
		}
		temp++;
	}
//	for(iter=s.begin();iter!=s.end();iter++)
//	{				
//		cout<<*iter<<endl;				
//	}
	return 0;
}

非set版:
字典序:
(符号竟是试出来的)

int cmp(string a,string b)
{
	if(a.size()!=b.size()) return a<b;
	else return a+b<b+a;	
}

总代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int cmp(string a,string b)
{
	if(a.size()!=b.size()) return a<b;
	else return a+b<b+a;	
}
int main()
{
	string a;cin>>a;
	int k;cin>>k;
	int len=a.size();
	int k1=min(k,len);
	string str[N];
	int sum=0;
	for(int i=0;a[i];i++)
	{
		string c;
		for(int j=i;j<=i+k1&&a[j];j++)
		{
			c+=a[j];
			str[sum++]=c;
		}
	}
	sort(str,str+sum,cmp);
	unique(str,str+sum);
	int sum1=0;
//	for(int i=0;i<sum;i++)
//	{
//		cout<<str[i]<<endl;
//	}
	cout<<str[k-1];
	return 0;
}

ps:如果用string c自己加一个string出来,竟然无法用set去重,有点疑惑。

G - Attention

原题
大意:一排人面向西边或东边。选一个人做leader,其他人都要面向他。求转向最少的。
leader左边的人要为E,右边的人要为W

暴力T了一发。然后想到用前缀和

w代表此人左边的W,e代表此人右边的E。ww代表此人是W,ee代表此人是E。
求出每一个leader左边所有E和右边所有W的最大值,即得到要转身的最小值。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5;
struct node
{
	char op;
	int w=0,e=0;
	int ww=0,ee=0;
}a[N];
//左E右W 
int main()
{
	int n;cin>>n;
	
	for(int i=1;i<=n;i++)
	{
		char op;cin>>op;
		a[i].op=op;
		if(op=='W') a[i].ww++;
		else a[i].ee++;
		
		a[i].e+=a[i-1].e+a[i-1].ee;
		a[i].w+=a[i-1].w+a[i-1].ww;		
	}
	if(a[n].ww) a[n].w++;	
	
	int sum=0,ans=0;
	for(int i=1;i<=n;i++)
	{
		int tempw;
		if(a[i].op=='W') tempw=a[n].w-a[i].w-1;
		else tempw=a[n].w-a[i].w;
		if(tempw<0) tempw=0;		
		sum=tempw+a[i].e;
		ans=max(ans,sum);
	} 	
	ans=n-ans-1;
	if(ans<0) ans=0;
	cout<<ans;
	return 0;
}

以上是关于复盘7.8训练的主要内容,如果未能解决你的问题,请参考以下文章

编程初级训练营复盘

复盘7.6训练

复盘7.12训练

复盘8.17训练:UCF Local Programming Contest Final Round

复盘7.21训练:UCF Local Programming Contest Round 1A

听说多肉站案例不能采集了,那自行建设一个吧。爬虫120例复盘之战