A. Prof. Slim
分析
一个数组,可以选i,j两个数,这两个数正负号不能相同,使这两个数交换符号,是否可以将这个数组变成递增数组。
因为交换必须两个符号不同,要考虑递增,就得让前面的数变成负数,而且原来有几个负数,操作后还是几个负数,所以记录负数个数,将数组前面的数都修改为负数,判断一遍是否为递增,如果现在仍不为递增,则无法操作后将数组变为递增数组。
代码
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
using namespace std;
const ll maxn=1e5+10;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const double pi=acos(-1);
int a[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
int f=1;
int cnt=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]<0)
{
a[i]=abs(a[i]);
cnt++;
}
}
for(int i=1;i<=cnt;i++)
{
a[i]*=-1;
}
for(int i=1;i<n;i++)
{
if(a[i]>a[i+1])
{
f=0;
break;
}
}
if(f) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
B. Dorms War
分析
一个字符串,给一些字符,每次可以删掉这些字符的前一个字符,求删到没有可以删的时候,进行了几次操作。
因为可以一直删,每次可以删好几个字符。所以其实就是找出两个给出字符之间的最大长度。
注意:cin,cout要关流,不然会t!!!
代码
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
using namespace std;
const ll maxn=1e5+10;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const double pi=acos(-1);
/*ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);*/
int a[30];
char s[maxn];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--)
{
memset(a,'\0',sizeof(a));
int n,k,pos=0;
cin>>n>>s>>k;
int ans=0;
for(int i=1;i<=k;i++)
{
char tmp;
cin>>tmp;
a[tmp-'a']=1;
}
for(int i=n-1;i>=0;i--)
{
if(pos)
{
ans=max(ans,pos-i);
}
if(a[s[i]-'a'])
{
pos=i;
}
}
cout<<ans<<endl;
}
return 0;
}
C. Where is the Pizza?
分析
a,b数组分别为两个排列,c数组为0,则从ab中同一位置,选一个数,使c数组成为一个合法的排列序列,求多少种选法。
对于每个位置,都有选和不选两种,我们只要考虑需要考虑多少个这样的位置。由于要成为合法的排列,所以对于每个c数组为0的位置需要考虑,ab是否相等(相等则无法选择);前面的选取是否对后面的选取有影响。这个影响我们采用并查集记录,将ab不同的两个数修改为同一个父节点,当再次查到这两个数时,他们不为可选的位置。最后只需要查找有多少个父节点,即多少个可选择的位置,快速幂求出2次方。
注意:快速幂开long long!
代码
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define guanliu ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const ll maxn=1e5+10;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const double pi=acos(-1);
ll fa[maxn],a[maxn],b[maxn],c[maxn];
ll n,cnt;
ll fastpow(ll k,ll a)
{
ll res=1;
while(k)
{
if(k&1)
{
res=res*a%mod;
}
k>>=1;
a=a*a%mod;
}
return res;
}
void init(int size) //初始化
{
cnt=0;
for(int i=0;i<=size;i++)
fa[i] = i; //i就在它本身的集合里
return;
}
int find(int x) // 查找
{
if(x!=fa[x]) //x不是自身的父亲,即x不是该集合的代表
fa[x]=find(fa[x]); //查找x的祖先直到找到代表,于是顺手路径压缩
return fa[x];
}
void unionSet(int x, int y) //合并
{
//x与y所在家族合并
x=find(x);
y=find(y);
fa[x]=y; // 把x的祖先变成y的祖先的儿子
}
int main()
{
guanliu;
int t;
cin>>t;
while(t--)
{
cin>>n;
init(n);
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
cin>>b[i];
}
for(int i=1;i<=n;i++)
{
cin>>c[i];
}
for(int i=1;i<=n;i++)
{
if(a[i]==b[i])
{
fa[a[i]]=0;
}
unionSet(a[i],b[i]);
}
for(int i=1;i<=n;i++)
{
fa[find(c[i])]=0;
}
for(int i=1;i<=n;i++)
{
if(fa[i]==i) cnt++;
}
//cout<<cnt<<" ";
cout/*<<"ans:"*/<<fastpow(cnt,2)%mod<<endl;
}
return 0;
}
D. Very Suspicious
分析
在六边形图上,增加线构成等边三角形,求出最少需要几条线可以构成n个等边三角形。
一个六边形加三条线,变成6个三角形,只有这三条线可以构成等边三角形,预处理id条线最多可以构成多少个三角形,二分查找一下答案。
代码
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define guanliu ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const ll maxn=5e5+10;
const ll mod=1e9+7;
const ll INF=0x3f3f3f3f;
const double pi=acos(-1);
int n,ans[maxn];
void pre()
{
ans[2]=2;
ans[3]=6;
int id=0;
int cnt[3]={1,1,1};
for(int i=4;i<=4e4;i++)
{
id=i%3;
ans[i]=ans[i-1];
for(int j=0;j<3;j++)
{
if(j!=id) ans[i]+=2*cnt[j];
}
cnt[id]++;
}
}
int main()
{
pre();
guanliu;
int t;
cin>>t;
while(t--)
{
cin>>n;
cout<<lower_bound(ans+1,ans+1+40000,n)-ans<<endl;
}
return 0;
}