A
键盘按钮有的坏了,坏了的按一下出两个字母,现在给出打印好的字符串,判断好的按钮有哪些,按字典序输出。
思路:暴力求解
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
char ch[505];
while(t--)
{
scanf("%s",ch+1);
int len=strlen(ch+1);
int cnt=1;
int pos=1;
set<char>p;
while(1)
{
cnt=1;
while(1)
{
if(ch[pos]==ch[pos+1])
{
cnt++;
pos++;
continue;
}
else break;
if(pos>len) break;
}
if(cnt&1)
{
p.insert(ch[pos]);
pos++;
}
else pos++;
if(pos>len) break;
}
if((int)p.size()>0)
{
set<char>::iterator it;
for(it=p.begin();it!=p.end();it++)
printf("%c",(*it));
}
printf("\n");
}
return 0;
}
B
给n个字符串,由01组成,每次操作可任意选两个或一个字符串,若选两个,可相互交换任意位置上的元素,在两个字符串之间,若选一个,可以任意交换这个字符串上的元素。问最多能得到多少回文字符串。
思路:只有存在偶数长度的字符串且这个字符串由奇数个1奇数个0的时候,如果没有奇数长度的字符串给他搭配,那么他将变不成回文,如果存在奇数长度的字符串,那么这个字符串可以反复使用,来使其他变回文,若没有奇数长度的串,且0的个数为奇数,1的个数为技术,那么必有一个串符合最开始描述的那种变不成的情况。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
char s[55];
int jud=0;
int cnt[2]={0};
for(int i=1;i<=n;i++)
{
scanf("%s",s);
int len=strlen(s);
if(len&1) jud=1;
for(int j=0;j<len;j++)
{
cnt[s[j]-'0']++;
}
}
if(cnt[0]%2&&cnt[1]%2&&jud==0)
n--;
printf("%d\n",n);
}
return 0;
}
C
给一串字符串,看成一个数,每次操作可交换相邻的奇偶不同的两个元素,问最小字典序的串是什么。
思路:这道题我蠢到用模拟去做,哎。其实,奇偶不同不能换,那么奇数与奇数相对位置不变,偶数也这样,分别放两个组里,然后来回比较大小。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[300005];
char ch1[300005];
char ch2[300005];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",s+1);
int len=strlen(s+1);
int pos1=0,pos2=0;
for(int i=1;i<=len;i++)
{
if((s[i]-'0')&1)
ch1[++pos1]=s[i];
else ch2[++pos2]=s[i];
}
int p1=1;
int p2=1;
while(p1<=pos1||p2<=pos2)
{
if(ch1[p1]<ch2[p2]&&p1<=pos1&&p2<=pos2)
{
printf("%c",ch1[p1]);
p1++;
}
else if(ch1[p1]>ch2[p2]&&p1<=pos1&&p2<=pos2)
{
printf("%c",ch2[p2]);
p2++;
}
else if(p1>pos1)
{
printf("%c",ch2[p2]);
p2++;
}
else if(p2>pos2)
{
printf("%c",ch1[p1]);
p1++;
}
}
printf("\n");
}
return 0;
}
D
给n个范围,(l,r),给一个数s,把这个数拆成n个数,且每个数都符合各自的范围,s可以不用完,问这n个数的最大中位数是什么。
思路:二分中位数,看能否满足中位数的条件,并且判断和值是否超过了s。进而确定二分区间。`
#include <iostream>
#include<cstdio>
#include<cstring>
#include<utility>
#include<algorithm>
#define ll long long
using namespace std;
const int N=2e5+5;
pair<ll,ll>a[N];
ll s;
int n;
int num;
bool jud(ll mid)
{
ll cost=0;
int cnt=0;
for(int i=0;i<n;i++)
{
if(a[i].first>=mid)
{
cnt++;
}
else if(a[i].second>=mid)
{
cost=cost+mid-a[i].first;
cnt++;
}
if(cost>s) return 0;
if(cnt==num) return 1;
}
return 0;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--)
{
cin>>n>>s;
for(int i=0;i<n;i++)
cin>>a[i].first>>a[i].second;
sort(a,a+n,greater<pair<ll,ll>>());
ll l=a[n/2].first;
ll r=s;
num=(n+1)/2;
ll ans=0;
for(int i=0;i<n;i++)
{
s=s-a[i].first;
}
while(l<=r)
{
ll mid=(l+r)>>1;
if(jud(mid))
{
l=mid+1;
ans=mid;
}
else r=mid-1;
}
cout<<ans<<endl;
}
return 0;
}
E
有n个人,每人一张选票,若使得他投给你,可以花pi的钱收买,若有mi个人投了你,则第i个人也会投你,问你要让所有人投你,最少花多少钱。
思路:
只有先收买m值大的,然后m值小的才有可能不花钱,若几个人的m值一样,就买小的那个,但要保证,买完后要使没买的那几个免费投你。
那么,也就是说,有4个人m值为7,一共10个人,那么你要买一个人,这样的话剩下的那三个人就能免费投你,因为已经有七个人投了你。
哎,绕了一晚上。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#define ll long long
using namespace std;
const int N=5005;
vector<ll> v[N];
int main()
{
int t;
scanf("%d",&t);
int n;
while(t--)
{
priority_queue<ll,vector<ll>,greater<ll> >q;
scanf("%d",&n);
for(int i=0;i<=n;i++) v[i].clear();
int m;ll p;
for(int i=1;i<=n;i++)
{
scanf("%d%lld",&m,&p);
v[m].push_back(p);
}
ll res=0;
for(int i=n-1;i>=0;i--)
{
for(int j=0;j<(int)v[i].size();j++)
{
q.push(v[i][j]);
}
while(q.size()>n-i)
{
res=res+q.top();
q.pop();
}
}
printf("%lld\n",res);
}
return 0;
}
F
有a个白木板,b个红木板,长短不一,要求红的长度最长处于中心位置且只有一个,左边的单调递增,右边的单调递减,左右都是白的。木板宽度为1,给出木板周长,有多少种木板的组合方案。
思路:题解里的dp方程比较好理解,但是NTT头一次见。题解里把dp和NTT衔接,衔接的很巧妙,NTT的模板没搞熟悉,还要再看看,不过倒是可以直接保存起来,拷贝直接用。