C Constructive Problems Never Die
题意
具有长度为n的序列A。 请找出一个序列P,P序列从1到你,且不重复,使得每个pi都不等于ai。
思路
使用pair存储A的值和序列,再对A根据值进行排序。如果a[1]=a[n],则无解。否则,设定hou=n,给b序列的b[a[i].second]填数,并满足b[a[i].second]不等于a[i].first,如果相等则将该数存入队列bu中,当hou减为0时,开始从队列中填数,如果最后一个无法填入,再从前边b[a[i].second]中选择合适的值进行交换。
代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <deque>
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define int long long
using namespace std;
pair<int,int> a[100005];
int b[100005];
deque<int>bu;
signed main()
{
IOS;
int t;
cin>>t;
int i,j;
int qian,hou;
int n;
while(t--)
{
bu.clear();
cin>>n;
qian=1;
hou=n;
for(i=1;i<=n;i++)
{
cin>>a[i].first;
a[i].second=i;
}
sort(a+1,a+n+1);
if(a[1].first==a[n].first)
{
cout<<"NO\n";
continue;
}
for(i=1;i<=n;i++)
{
if(hou==0)
{
break;
}
if(hou!=a[i].first)
{
b[a[i].second]=hou;
hou--;
}
else
{
bu.push_back(hou);
hou--;
if(hou==0)
{
break;
}
b[a[i].second]=hou;
hou--;
}
}
for(;i<=n;i++)
{
if(bu.front()!=a[i].first)
{
b[a[i].second]=bu.front();
bu.pop_front();
}
else if(bu.back()!=a[i].first)
{
b[a[i].second]=bu.back();
bu.pop_back();
}
else
{
break;
}
}
if(i<=n)
{
for(j=1;;j++)
{
if(b[a[j].second]!=a[n].first&&a[j].first!=bu.front())
{
b[a[n].second]=bu.front();
bu.pop_front();
swap(b[a[n].second],b[a[j].second]);
break;
}
}
}
cout<<"YES\n";
for(i=1;i<=n;i++)
{
cout<<b[i]<<" ";
}
cout<<endl;
}
return 0;
}
F Candies
题意
格莱美有一个圆形数组a1,a2,……,an。您可以多次(可能是零次)执行以下操作: 1.选择两个相邻的相同数字的位置,并擦除它们。 2.选择两个相邻的位置,使这两个位置上的数字加起来是一个特殊的数字x,并擦除它们。每次你操作成功后,格莱美会给你一颗糖。同时,数组的剩余部分将被连接起来。例如,在删除数组的第三和第四个元素后,第二个元素和第五个元素将变得相邻。找到你能得到的最大数量的糖果。 两个位置u,v(u<v)相邻当且仅当u+1=v或u=1,v=L,其中L为剩余数组的长度。
思路
考虑能消的所有情况,a[i]=a[i+1]或a[i]+a[i+1]=x,采用deque进行存储,在存储过程中如果发现队列的最后一个元素与要加入的元素满足上述情况,则删掉队尾元素,要加入的元素不入队,否则入队。最后,要考虑此为圆形数组,首位与末尾可能出现能消的情况,则将它们消掉,继续判断,直至无法消掉时退出循环。
代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <deque>
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define int long long
using namespace std;
deque<int>a;
signed main()
{
IOS;
int n,x;
cin>>n>>x;
int i,j;
int temp;
int sum=0;
for(i=1;i<=n;i++)
{
cin>>temp;
if(a.empty())
{
a.push_back(temp);
}
else
{
if(a.back()==temp||a.back()+temp==x)
{
sum++;
a.pop_back();
}
else
{
a.push_back(temp);
}
}
}
while(a.size()>=2)
{
if(a.front()==a.back()||a.front()+a.back()==x)
{
sum++;
a.pop_back();
a.pop_front();
}
else
{
break;
}
}
cout<<sum<<endl;
return 0;
}
G Regular Expression
题意
格莱美最近对正则表达式感兴趣,同时关注字母由a到z的字符组成的情况。今天她问了NIO一些问题。每道题给字符串A,根据匹配规则和所有最短表达式的个数,问与字符串A匹配的表达式的最小长度。这里我们只考虑从‘a’到‘z’的字符,'.', '?', '*', '+', '|', '(', ')'。假设星号、问号、加号优先级最高,然后串联,然后交替。括号可以用来改变优先级。本题是给定一个字符串A,求它的最短正则表达式的长度和数量。
思路
一看就懂:正则表达式_zyqok的博客-CSDN博客_正则表达式?!正则表达式中的*,+,?,^ , $,范围和次数用法_咦咦咦咦咦的博客-CSDN博客_正则+
通过这两个博客对正则表达式有一个基础的了解。
当字符串中只有一个字符时,最短正则表达式为它本身或.(.表示“\n”和"\r"之外的任何单个字符),此时输出 1 2 。当字符串中只有两个字符时,如果这两个字符相等都为x,则最短正则表达式可以为 xx,x. ,.x ,x+ ,x* ,.* ,.+ ,.. 共8种,此时输出2 8 ;如果这两个字符不相等时,则最短正则表达式可以为 xy ,.. ,x. ,.x ,.* ,x* ,此时输出 2 6 (+表示匹配到一个或者多个,*表示匹配到0个或者多个,所以当字符相同时,可以出现+表示x必定有重复,可以出现*表示重复;而当字符不同时,不能出现+,此时*号表示不出现前字符,直接加入新字符)。当字符串中字符多余两个时,最短正则表达式长度是 2,通过.*或.+可以表现整个字符,如果整个串相同,还可以用x*和x+来表示。
代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <deque>
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define int long long
using namespace std;
char s[200005];
signed main()
{
IOS;
int t;
cin>>t;
int i,j;
int n;
int op;
while(t--)
{
cin>>s;
n=strlen(s);
if(n==1)
{
cout<<"1 2\n";
}
else if(n==2)
{
if(s[0]==s[1])
{
cout<<"2 8\n";
}
else
{
cout<<"2 6\n";
}
}
else
{
sort(s,s+n);
if(s[0]==s[n-1])
{
cout<<"2 4\n";
}
else
{
cout<<"2 2\n";
}
}
}
return 0;
}