2020多校第八场(南昌理工ACM集训队)
1003
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
typedef long long ll;
const int INF=0x3f3f3f3f;
int main(){
int t;
scanf("%d",&t);
while(t--){
double x1,y1,x2,y2,x3,y3;
scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3);
double b = y1-(y1-y3)/(x1-x3)*x1;
if((y1-y3)/(x1-x3)>0){
if(y3>y1&&x3>x1&&(y2-(y1-y3)/(x1-x3)*x2-b)>0){
//a在下
printf("Clockwise\n");
continue;
}
if(y3<y1&&x3<x1&&(y2-(y1-y3)/(x1-x3)*x2-b)<0){
printf("Clockwise\n");
continue;
}
}else if((y1-y3)/(x1-x3)<0) {
if(y3>y1&&x3<x1&&(y2-(y1-y3)/(x1-x3)*x2-b)<0){
printf("Clockwise\n");
continue;
}
if(y3<y1&&x3>x1&&(y2-(y1-y3)/(x1-x3)*x2-b)>0){
printf("Clockwise\n");
continue;
}
}
if((y1-y3)/(x1-x3)==0){
if((x2-x1)>0&&y3<y1&&x3<x1){
printf("Clockwise\n");
continue;
}
if((x2-x1)<0&&y1<y3&&x1<x3){
printf("Clockwise\n");
continue;
}
}
printf("Counterclockwise\n");
}
return 0;
}
1006
思路:先正着更新一遍再倒着更新一遍
用x[i]记录第i段的起始位置,用y[i]记录末位置
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
typedef long long ll;
inline ll read()
{
ll s=0,w=1;char ch=getchar();
while(ch<48||ch>57){
if(ch=='-')w=-1;ch=getchar();}
while(ch>=48&&ch<=57)s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*w;
}
int x[N],y[N],t,n,k;
bool f;
int main()
{
t=read();
while(t--)
{
f=0;
n=read(),k=read();
for(int i=0;i<n;i++)x[i]=read(),y[i]=read();
for(int i=1;i<n;i++)
{
x[i]=max(x[i],x[i-1]-k);
y[i]=min(y[i],y[i-1]+k);
if(y[i]<x[i])
{
f=1;
break;
}
}
if(f)cout<<"NO\n";
else
{
cout<<"YES\n";
for(int i=n-1;i>0;i--)
{
x[i-1]=max(x[i-1],x[i]-k);
y[i-1]=min(y[i-1],y[i]+k);
}
for(int i=0;i<n-1;i++)cout<<x[i]<<' ';
cout<<x[n-1]<<endl;
}
}
return 0;
}
1008
思路:找规律
n=3时,答案可以是324213162651546432
n=4时,答案可以是324242131316262651515464643532321653
n=5时,答案可以是324242421313131626262651515154646464353532324213162651546432
可以发现每次输出最外面2层,可以用dfs(n-2)再继续输出
#include<iostream>
using namespace std;
int t,n;
void dfs(int x)
{
if(x==2)
{
cout<<"321653\n";//注意这里要变成这个,而不是样例里的答案
//因为我用的顺序和题目样例的不一样
return;
}
if(x==3)
{
cout<<"324213162651546432\n";
return;
}
//6条边,分段输出
//可以多举几个例子就会发现规律了
cout<<"32";
for(int i=1;i<=x-2;i++)cout<<"42";
cout<<'1';
for(int i=1;i<=x-2;i++)cout<<"31";
cout<<'6';
for(int i=1;i<=x-2;i++)cout<<"26";
cout<<'5';
for(int i=1;i<=x-2;i++)cout<<"15";
cout<<'4';
for(int i=1;i<=x-2;i++)cout<<"64";
cout<<'3';
for(int i=1;i<=x-3;i++)cout<<"53";
cout<<'2';
dfs(x-2);
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
dfs(n);
}
return 0;
}
1009
思路:由于题目时间限制为8000ms,所以可以考虑暴力,但要减枝;
既然要把字符串分为n/k个子串,那么每个子串中都要包含原s串里出现过的每种字符,因此,统计s串中不同种类字符的个数,取他们共同的最大公因数m,
再枚举m的因数作为子串个数(这样就保证了每种字符都平均的分配到每个子串中,这样子串两两之间才有互为循环同构的可能),
然后利用kmp算法判断n/k个子串是否两两之间为循环同构(以第一个子串为主串),注意k>1与字符种类数为1的情况要特判。
为什么要用kmp呢?
因为把第一段重复一段
比如第一段为asdfg
要比较的为sdfga
把第一段变为asdfgasdfg
再用kmp就行了
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+5;
int n,t;
int kmp(string S,string T)//kmp模板
{
int Slen,Tlen,Next[T.length()+10];
Slen=S.length(),Tlen=T.length();
int i,j=-1;
Next[0]=-1;
for(i=1;i<Tlen;i++){
while(j>-1&&T[j+1]!=T[i])
j=Next[j];
if(T[j+1]==T[i])
j++;
Next[i]=j;
}
j=-1;
for(i=0;i<Slen;i++){
while(j>-1&&T[j+1]!=S[i])
j=Next[j];
if(T[j+1]==S[i])
j++;
if(j==Tlen-1)return 1;
}
return 0;
}
map<int,int>vis,num;
int k;
bool p,f;
string s;
int main()
{
cin>>t;
while(t--)
{
int m;
k=0;
vis.clear();
num.clear();//清零
scanf("%d",&n);
cin>>s;
if(n==1)//n=1时特判
{
cout<<"No\n";
continue;
}
for(int i=0;i<n;i++)
{
num[s[i]]++;//每个元素出现的次数
if(!vis[s[i]])
{
vis[s[i]]=1;
k++;//有多少个元素
}
}
p=0,f=0;
if(k==1){
cout<<"Yes\n";continue;}
//如果只有一种元素,显而易见输出yes
for(auto &it:num)
{
int i=it.second;
if(!p)m=i;
else
{
m=__gcd(m,i);//求最大公因数
if(m==1)break;
}
p=1;
}
for(int i=2;i<=m;i++)
{
if(n%i)continue;
string ss=s.substr(0,n/i);
ss+=ss;//把第一段补一段
for(int j=2;j<=i;j++)
{
if(kmp(ss,s.substr(n/i*(j-1),n/i)))
{
f=1;
break;//但凡有一个符合条件直接跳出输出yes
}
}
if(f)break;
}
if(f)cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}