A.Bobo String Construction
s取全0串或者全1串,至少有一者满足题述条件
大致感受一下
随便举几个例子:
t s t
0000|0000|0000 s为全0不符合,但s为全1符合
1001|00|1001 s为全0不符合,但s为全1符合
101|000000|101 s为全0或为全1均符合
所以只需判断全0串或者全1串哪个符合题述条件即可(只要判断一方即可,一方不符合就是另一方)
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
int n;
void solve() {
cin>>n;
string t;
cin>>t;
string s(n,'0');
string ss(n,'1');
string str=t+s+t;
if(str.find(t,1)!=t.size()+s.size()) cout<<ss<<endl;
else cout<<s<<endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}
或者用kmp算法在文本串匹配模式串
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=1010;
int ne[N];
int n;
void solve() {
cin>>n;
string t;
cin>>t;
string s(n,'0');
string ss(n,'1');
string str='0'+t+s+t;
int len1=t.size();
int len2=t.size()+n+t.size();
t='0'+t;
//求next值
for(int i=2,j=0;i<=len1;i++){
while(j&&t[i]!=t[j+1]) j=ne[j];
if(t[i]==t[j+1]) j++;
ne[i]=j;
}
//文本串匹配模式串
bool ok=true;
for(int i=1,j=0;i<=len2;i++){
while(j&&str[i]!=t[j+1]) j=ne[j];
if(str[i]==t[j+1]) j++;
//找到了模式串
if(j==len1){
//i表示文本串匹配到了哪一位
if(i!=len1&&i!=len2){
ok=false;
break;
}
}
}
if(ok) cout<<s<<endl;
else cout<<ss<<endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}
F.Election of the King
先从小到大排个序,然后每次肯定要么删第一个数,要么删最后一个数
我们先求出第一个数(最小的数)和最后一个数(最大的数)的平均值x,然后求出大于x的数有几个,小于等于x的数有几个,如果大于x的数多,那么就删掉第一个数,否则就删掉最后一个数
将运行轨迹输出出来,方便检查
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<cstdio>
#define endl '\n'
//#define int long long
typedef long long ll;
using namespace std;
typedef pair<int,int>PII;
int n;
void solve()
{
cin>>n;
vector<PII>ans;
for(int i=1;i<=n;i++){
int x;
cin>>x;
ans.push_back({x,i});
}
sort(ans.begin(),ans.end());
int p=0,q=n-1;
while(p<q){
int x=ans[p].first+ans[q].first;
int l=p,r=q;
while(l<r){
int mid=(l+r)/2;
if(ans[mid].first*2>x) r=mid;
else l=mid+1;
}
// cout<<p<<" "<<q<<" "<<l<<endl;
if(q-l+1>l-p) p++;
else q--;
}
cout<<ans[p].second<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
// cin>>t;
while(t--)
solve();
return 0;
}
L.We are the Lights
法一:先预处理操作的行的最终状态和列的最终状态
然后按照先后顺序进行枚举,由于记录的都是最终状态,也就是说操作的每一行以及每一列都只会操作一次(不会重复操作)
如果开了一列灯,那么就加上(n-开了几行灯)
如果开了一行灯,那么就加上(m-开了几列灯)
如果关了一列灯,那么就减去开了几列灯
如果关了一行灯,那么就减去开了几列灯
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<cstdio>
#include<set>
#define endl '\n'
//#define int long long
typedef long long ll;
using namespace std;
typedef pair<int,int>PII;
const int N=1e6+10;
int n,m,q;
struct node{
int kind;//0表示行,1表示列
int x;
int status;//0表示关灯,1表示开灯
}s[N];
bool st[N];
int cnt[N];
void solve()
{
cin>>n>>m>>q;
//预处理,记录操作的行的最终状态以及列的最终状态
for(int i=0;i<q;i++){
string s1,s2;
int x;
cin>>s1>>x>>s2;
if(s1=="row"){
if(s2=="on") s[i]={0,x,1};
else s[i]={0,x,0};
}
else{
if(s2=="on") s[i]={1,x,1};
else s[i]={1,x,0};
}
}
set<PII>se;
for(int i=q-1;i>=0;i--){
int kind=s[i].kind,x=s[i].x;
if(!se.count({kind,x})){
se.insert({kind,x});
st[i]=true;
}
}
ll res=0;
for(int i=0;i<q;i++){
if(!st[i]) continue;
//开灯
if(s[i].status==1){
cnt[s[i].kind]++;//cnt[0]记录开了几行灯,cnt[1]记录开了几列灯
if(s[i].kind==1) res+=n-cnt[0];//如果开了一列灯,那么就加上(n-开了几行灯)
else res+=m-cnt[1];//如果开了一行灯,那么就加上(m-开了几列灯)
}
//关灯
else{
if(s[i].kind==1) res-=cnt[0];//如果关了一列灯,那么就减去开了几列灯
else res-=cnt[1];//如果关了一行灯,那么就减去开了几列灯
}
}
cout<<res<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
// cin>>t;
while(t--);
solve();
return 0;
}
换一种写法:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<set>
#include<cstdio>
#define endl '\n'
//#define int long long
typedef long long ll;
using namespace std;
const int N=1e6+10;
int n,m,q;
struct node{
string s1;
int x;
string s2;
}s[N];
bool ok[N];
void solve()
{
cin>>n>>m>>q;
for(int i=0;i<q;i++) cin>>s[i].s1>>s[i].x>>s[i].s2;
set<pair<string,int>>se;
for(int i=q-1;i>=0;i--){
string s1=s[i].s1;
int x=s[i].x;
if(!se.count({s1,x})){
se.insert({s1,x});
ok[i]=true;
}
}
int row=0,col=0;
ll res=0;
for(int i=0;i<q;i++){
if(!ok[i]) continue;
if(s[i].s2=="on"){
if(s[i].s1=="row"){
res+=m-col;
row++;
}
else{
res+=n-row;
col++;
}
}
else{
if(s[i].s1=="row") res-=col;
else res-=row;
}
}
cout<<res<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
// cin>>t;
while(t--)
solve();
return 0;
}
法二:
从后往前推,同理也是要知道操作的行和列的最终状态,不过呢,由于在后面的肯定是最终状态,所以当枚举到某行或某列是第一次出现时,那么就是最终状态,标记一下,如果后面再出现已经标记过的行或列时,就直接continue
我们先知道后面的状态,比如说后面的状态是对一列进行关灯操作,那么如果前一操作是开灯操作,那么它开的数量就是(n-开灯的列数),实际上根本不用管后一操作是开灯还是关灯,只要后面操作了,前一次操作操作同样的地方就白操作了,所以只要记录后面状态操作的行的次数以及操作的列的次数就行了
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<set>
#include<cstdio>
#define endl '\n'
//#define int long long
typedef long long ll;
using namespace std;
const int N=1e6+10;
int n,m,q;
struct node{
string s1;
int x;
string s2;
}s[N];
int row[N];
int col[N];
void solve()
{
cin>>n>>m>>q;
for(int i=0;i<q;i++) cin>>s[i].s1>>s[i].x>>s[i].s2;
int cnt1=n;//还剩几行在后面没被操作过,也就是有几行操作是有效的
int cnt2=m;//还剩几列在后面没被操作过,也就是有几列操作是有效的
//由于我们只要求灯亮的数量,所以我们只要知道开灯操作有哪些是有效的就行,不需要考虑关灯
ll res=0;
for(int i=q-1;i>=0;i--){
int x=s[i].x;
if(s[i].s2=="on"){
if(s[i].s1=="row"){
if(row[x]) continue;
res+=cnt2;
}
else{
if(col[x]) continue;
res+=cnt1;
}
}
if(!row[x]&&s[i].s1=="row") {
row[x]=1;
cnt1--;
}
else if(!col[x]&&s[i].s1=="column"){
col[x]=1;
cnt2--;
}
}
cout<<res<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
// cin>>t;
while(t--)
solve();
return 0;
}