Not a Substring(Problem - A - Codeforces)
题目大意:给一个由括号组成长为n的字符串s,我们要找出一个长度为2*n的字符串a,使得a中的括号是配对的,同时s不是a的子串。
思路:很显然我们面对的情况有限,可以落到两个字符之间来看:
():这种没法处理,因为只要是配好对的括号,一定会出现这个结构
)(:如果出现这个结构,可以补成(())
剩下的情况那么就是左括号在右括号左边的,我们全部拆散即可。
#include
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
string s;
cin>>s;
if(s=="()") printf("NO\n");
else
{
printf("YES\n");
int r=0,c=0;
for(int i=0;i
Fancy Coins(Problem - B - Codeforces)
题目大意:现在有价值为1的普通硬币a1个花式硬币无限个,价值为k的硬币a2个花式硬币无限个,要求恰好凑出m,问至少用多少个花式硬币。
思路:这题很容易想到dp,就先将两种普通硬币能凑出来的数统计出来,然后找一个最近的用花式硬币去补,但是很显然,这个最近的就有说法了,如果只用1枚价值k的硬币显然比用三枚价值1的花式硬币划算,但是后一种情况距m更近。但是我们很容易发现,这里求的是花式硬币的最小个数,那么很显然合法情况有很多,故而我们使用二分查找。check函数检查凑出m需要补多少个硬币,肯定优先补价值k的花式硬币,如果差值小于k之后再补价值为1的花式硬币,
#include
using namespace std;
int m,k,a,b;
int check(int mid)
{
int s=m/k;
int r=m%k;
int ta=a-r,tb=b-s;
if(ta>=0&&tb>=0) return 1;
else if(ta>=0)
{
//b<0
int d=0-tb;
if(a/k)//a/k表示剩余的a能补几个k
{
d -= ta/k;
d=max(0,d);
}
if(d<=mid) return 1;
else return 0;
}
else if(tb>=0)
{
int d=0-ta;
if(d<=mid) return 1;
else return 0;
}
else
{
int d=0-ta+0-tb;
if(d<=mid) return 1;
else return 0;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&m,&k,&a,&b);
int l=0,r=m;
while(l
ps:这题真的很像贪心题,也确实在check的时候用到了贪心策略,但是唯一的贪心就是如果价值为1的普通硬币有多的可以去补价值为k的普通硬币不足的部分,除此之外,本质上考的还是二分,就跟之前那个打饭题一样,看似要找最优策略,实际上只有很简单的一步用到贪心,本质上还是一个二分题,判断二分出来的结果是否合适。
Game on Permutation(Problem - C - Codeforces)
题目大意:有一个排列,A和B做游戏,A先移动,B后移动,A的第一次移动选择将芯片放在某一个数上,剩下的每次移动只能向左,同时移到一个严格小于当前数的数上去,谁不能进行移动,那么谁就赢了,我们将A选择的位置中,A必胜的位置视为幸运位置,问排列中有多少个幸运位置。
思路:很容易发现,我们相当于是找以某个点结尾的单增序列的最长长度,如果长度等于2,那么很显然,B移动一次,轮到A,那么A此时不能移动,胜利,如果等于长度等于1,显然B直接胜利,如果长度大于2,那么B可以将芯片移动到倒数第二个位置,A移动一次,然后B胜利,所以只有长度为2的时候,是幸运位置,但是有一点比较麻烦的是,这题的数据范围是t是1e4,n是3e5,那么需要用线性的时间复杂度来解决。于是就要用单调队列优化的方法处理最长上升子序列。这里我们在为每个字符找出来的r+1实际上也就是以它为结尾的最长上升子序列的长度。
#include
using namespace std;
int a[300010],q[300010],lh[300010],hh,tt;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int len=0;
for(int i=1;i<=n;i++)
{
int l=0,r=len;
while(l