唉,我真是菜的抠脚啊
B - Paths in a Complete Binary Tree
CodeForces - 792D
思路:
这题感觉就是找规律,模拟即可,没什么算法,反正我也做不出来可能,嘿嘿。
但是数据范围很大,必须要用位运算,而且注意1的地方用 1ll。
主要就是当遇到U时,判断当前结点是左孩子还是右孩子。(d自叶子往上从0开始编号)
看了别人写的是这样判断的 :flag = ((ans - (1ll << d)) / (1ll << (d + 1))) % 2;
我也没怎么理解其实,唉。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,q,ans;
char s[1000100];
int main()
{
scanf("%I64d%I64d",&n,&q);
char c;
while(q--)
{
scanf("%I64d%s",&ans,s);
ll p=(n+1)>>1ll;
ll d=log2(p);
while(ans!=p){
if(ans>p){
p+=1ll<<(d-1);
d--;
}
else{
p-=1ll<<(d-1);
d--;
}
}
int l=strlen(s);
for(int i=0;i<l;i++)
{
if(s[i]=='U')
{
ll flag = ((ans - (1ll << d)) / (1ll << (d + 1))) % 2;
if(flag){
ans-=(1ll<<d);
d++;
}
else if(!flag&&(1ll<<(d+1)<=n)){
ans+=(1ll<<d);
d++;
}
}
else if(s[i]=='L')
{
if(d>0){
ans-=(1ll<<(d-1));
d--;
}
}
else if(s[i]=='R')
{
if(d>0){
ans+=(1ll<<(d-1));
d--;
}
}
}
printf("%I64d\n",ans);
}
return 0;
}
D - Make Palindrome
CodeForces - 600C
题目大意:
给定一个字符串,用最少的次数将其变成回文串,字母改变位置不算操作次数。
思路:
记录每个字母出现的次数,然后从a开始往后扫描,遇到偶数跳过,遇到奇数就从z开始往前找到奇数个的字母,将其中的一个字母改变。
注意如果是只有一个奇数个字母,则无需改变了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2*1e5+10;
int main()
{
char s[maxn],ss[maxn];
int a[30]={0};
scanf("%s",s);
int l=strlen(s);
for(int i=0;i<l;i++)
a[s[i]-'a']++;
int cnt=0;
for(int i=0;i<26;i++) //找到有几个字母为奇数个
if(a[i]%2)
cnt++;
for(int i=0;i<26;i++)
{
if(a[i]%2)
{
if(cnt>1) //如果有一个以上的奇数个字母,先将字典序大的奇数个字母变成字典序小的
{
for(int j=25;j>i;j--)
{
if(a[j]%2)
{
a[i]++;
a[j]--;
cnt-=2;
break;
}
}
}
}
}
int flag=-1;
for(int i=0;i<26;i++)
{
if(a[i]%2)
{
flag=i;
a[i]--;
break;
}
}
for(int i=0;i<26;i++)
{
int k=a[i]/2;
while(k--)printf("%c",'a'+i);
}
if(flag!=-1)printf("%c",'a'+flag);
for(int i=25;i>=0;i--)
{
int k=a[i]/2;
while(k--)printf("%c",'a'+i);
}
return 0;
}
F - A Magic Lamp
HDU - 3183
题目大意:
给定一串数字,使在去掉m个数字后得到的数最小。
思路:
一开始老是想着去掉n - m个最大的数,其实这种思路是完全不对的,比如561289 2,最小应该是1289;
然后发现其实完全可以把其中最小的 m 个数找出来组成一个最小的数。
介于举的例子的情况,应该当需要取出m个最小数时,下一个要取的数是从当前位置 i 开始 n - m 个数中的最小值。
静态表查询最值可用ST表实现。
#include<bits/stdc++.h>
using namespace std;
int dp[1010][10];
char s[1010];
int Min(int x,int y)
{
if(s[x]<=s[y])return x;
else return y;
}
void rmq(int n)
{
for(int i=0;i<n;i++)
dp[i][0]=i;
for(int j=1;(1<<j)<n;j++){
for(int i=0;i+(1<<j)-1<n;i++){
dp[i][j]=Min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int query(int l,int r) //求l到r范围内的最小值
{
int k=(int)(log(r-l+1)/log(2));
return Min(dp[l][k],dp[r-(1<<k)+1][k]);
}
int main()
{
int m,a[1010];
while(cin>>s>>m)
{
int l=strlen(s),ma;
rmq(l);
m=l-m;
int i=0,cnt=0;
while(m--)
{
i=query(i,l-m-1); //m--,所以区间长度要+1
a[cnt]=s[i];
i++;cnt++;
}
for(i=0;i<cnt;i++)
if(a[i]!='0')
break;
if(i==cnt)printf("0");
else{
while(i<cnt)
printf("%c",a[i++]);
}
printf("\n");
}
return 0;
}