目录
E. Polycarp and String Transformation
写在前面——反思
这一场打的有点烂,值得反思反思,首先说一下A,做A的时候一直在推式子,在想关于模3或者(x-3) mod 10,还有容斥方面,后面发现有点麻烦,样例不对,才发现这数据可以打暴力...怪我把div3的A题想复杂了。B题是我蠢了,我大致方向是对的,就是有个判断条件没有加,第二发wa跟第一发没区别,加了一个恒成立的式子,白白浪费时间,这个题不应该耗这么久的时间。C题是一个原题,我以前做过,不过if的时候出了点差错,10min有点小多。D题差不多正常时间,这题不亏。
最让我心痛的是E,怪我,太菜,哎。推答案一推了很久都没有想明白,一开始的方向就错了,曹佬给出了提示我还是没有一下写出来。最让我遗憾的是时间不够了,我在比赛结束的一分钟内写出了程序,然后提交发现A了。但是,就是差这么一分钟,不多不少的一分钟。
在这张图里面有一个第四行,这是一个20级新生的成绩,有点愧疚,前面写的太慢,还wa了...真是不应该,B题花了太多时间,得到了太多罚时。
A. Dislike of Threes
题目链接
题意
求问前面n个数有多少个末尾不是3并且不是3的倍数
思路
直接暴力
代码
inline void Case_Test()
{
cin>>n;
int ans,cnt=0;
for (int i=1;;i++)
{
if (i%3==0||i%10==3) continue;
cnt++;
if (cnt==n) {ans=i;break;}
}
cout<<ans<<endl;
}
B. Who's Opposite?
题目链接
题意
一个这样的环形图,两两对应,已知其中一对,求c对应的哪个数,不满足则输出-1
思路
首先可以通过已知的一对数来求得一共有多少个,也可以求出一半是多少,如果c在后一半,那么它对应的就是前一半的,反之相反。
代码
inline void Case_Test()
{
cin>>a>>b>>c;
n=max(a,b)-min(a,b);
ma=n*2;
if (ma<max(a,b)||c>ma) {cout<<"-1"<<endl;return ;}
if (c>n&&c-n<=ma) {cout<<c-n<<endl;return ;}
if (c<=n&&c+n<=ma) {cout<<c+n<<endl;return ;}
cout<<-1<<endl;
}
C. Infinity Table
题目链接
题意
一个这样的图,求问图中x在多少行多少列
思路
发现左边一列是完全平方,第一行开始推,判断是下还是先下后左
代码
inline void Case_Test()
{
cin>>k;
n=(int)sqrt(k);
if (n*n==k)
{
cout<<n<<" "<<1<<endl;
return;
}
x=0;y=n+1;
tmp=k-n*n;
if (tmp<=n)
{
x+=tmp;
cout<<x<<" "<<y<<endl;
}
else
{
x=n+1;y=n+1;
tmp-=n+1;
y-=tmp;
cout<<x<<" "<<y<<endl;
}
}
D. Make a Power of Two
题目链接
题意
给出一个n,求问最少通过多少次操作能够使得n变为2的次方,操作有在右侧加数和删去任意一位
思路
因为给出的数据不大,我们可以首先打表把2的从1到63次方的表,不能通过数据来只打到31,因为有可能在右侧加入更多的数字来达到。
然后我们对于每一次数据都循环60多遍来判断,取min。
判断的话我们将这两个数字都转化成数组,这样容易一一比较,通过双指针来一一匹配,如果当前不满足,那么肯定是要删去的,指针向后移动,记一次数;如果当前相等的话,那么指针都往后,不计数,因为当前是匹配的。最后如果被匹配数指针没有取完,那么剩下的数是还要删去的,加上;如果最后匹配的指针没有取完,那么剩下的数是要在右侧加上的,加上。
最后输出答案。
代码
inline void init()
{
for (int i=1;i<=N;i*=2)
a[++cnt]=i;
int num=0;
for (int i=1;i<=N;i*=10)
b[++num]=i;
//预处理
}
inline int getlen(int x)
{
int ans=0;
while (x)
{
x/=10;
ans++;
}
return ans;
}
int c[20],d[20];
inline int check(int n,int x)
{
int num=0;
int len=getlen(n);
int l=getlen(x);
int t=x;
for (int i=l;i>=1;i--)
{
d[l-i+1]=t/b[i];
t%=b[i];
}
int cnt=1;
int i;
int ans=0;
for (i=1;i<=len;i++)
{
if (cnt>l) break;
if (c[i]==d[cnt]) {cnt++;continue;}
else ans++;
}
//cout<<ans+len+1-i+l+1-cnt<<endl;
return ans+len+1-i+l+1-cnt;
//ans是之前不匹配计数的 ans后面加的是指针还有多少未指完的个数
}
inline void Case_Test()
{
cin>>n;
int t=n;
int len=getlen(n);
for (int i=len;i>=1;i--)
{
c[len-i+1]=n/b[i];
n%=b[i];
}
int answer=inf,p;
for (int i=1;i<=cnt;i++)
{
//answer=min(answer,check(t,a[i]));
int m=check(t,a[i]);
if (answer>m) p=a[i],answer=m;
}
cout<<answer<<" "<<p<<endl;
}
E. Polycarp and String Transformation
题目链接
题意
一个字符串s,可以选择其中一个字符c让其s中删去所有的c,然后形成新的字符串s加到t右边(t一开始等于s),直到最后s为空。现在已知t,求问之前的字符串s还有删去的顺序,如果不存在那么就输出-1;
思路
这个题大部分归功于曹佬的提示,不然极大可能做不出来这个题。
答案2也就是顺序很容易得到,我们对于已知的字符串t的最后一位肯定是最后一个删除的,那么往前面扫,遇到第一个没有出现过的字符记录下来,因为这一个肯定是要删除的,不然后面不可能没有这个字符,所以记录下来,直到这个扫完,这个就出来的。
答案1这个我想了很久很久,最后在曹佬的提示下完成了,也就是说我们统计每一个字符出现了多少次,记cnt[i],假如字符'a'出现了3次,它是第一个删除的,那么原串(也就是答案1)有3个'a';假如字符'b'出现了4次,它是第二个删除的,那么其实它在原串中有两个'b',因为在一开始的时候有两个,然后删除'a'的时候它没有删除,又被假如到了字符串t中;假如字符'c'出现了6次,它是第三个删除的,那么同理'c'在原串中出现了2次......这样我们能得出所有的字符在原串中出现了多少次,那么我们可以一个for循环或者用字符串copy得到原串s。
注意:这时候原串不一定是正确答案,我们还得模拟一下操作最后得到的那个t判断是否与我们最开始已知的字符串相等,如果不相等就输出-1,反之输出答案1和答案2
代码
#include<stack>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<deque>
#include<vector>
#include<iostream>
#include<map>
#include<set>
#include<iomanip>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define debug(a) cout<<#a<<"="<<a<<endl;
#define eps 1e-8
using namespace std;
ll GCD(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const int inf=0x3f3f3f3f;
bool exist[200];
char ch,ans[200];
int tmp,l,a[200],num[200];
string s;
inline void Case_Test()
{
int cnt=0;
cin>>s;
l=s.length();
ch=s[l-1];
cnt=0;
ans[++cnt]=ch;
memset(exist,0,sizeof(exist));
memset(num,0,sizeof(num));
exist[ch]=1;
for (int i=l-2;i>=0;i--)
{
if (exist[ s[i] ]) continue;
exist[ s[i] ]=1;
ans[++cnt]=s[i];
a[ s[i] ]=cnt;
}
for (int i=0;i<l;i++)
num[s[i]]++;
int len=0;
//for (int i=cnt;i>=1;i--) cout<<ans[i]<<" "<<num[ans[i]]<<endl;
for (int i=1;i<=cnt;i++)
{
char c=ans[i];
int q=cnt+1-i;
num[c]/=q;
len+=num[c];
}
//for (int i=cnt;i>=1;i--) cout<<ans[i]<<" "<<num[ans[i]]<<endl;
//cout<<len<<endl;
string st="";
for (int i=0;i<len;i++) st+=s[i];
string answer=st;
//cout<<answer<<endl;
string tmp=st;
for (int i=cnt;i>=1;i--)
{
char c=ans[i];
for (int j=0;j<tmp.length();j++)
if (tmp[j]==c) tmp.erase(j,1),j--;
//cout<<tmp<<endl;
st+=tmp;
}
//cout<<st<<endl;
if (st!=s) {cout<<-1<<endl;return;}
cout<<answer<<" ";
for (int i=cnt;i>=1;i--) cout<<ans[i];
cout<<endl;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("IO\\in.txt","r",stdin);
freopen("IO\\out.txt","w",stdout);
clock_t start, end;
start = clock();
#endif
IOS
int _=1;
cin>>_;
while (_--)
{
Case_Test();
}
#ifndef ONLINE_JUDGE
end = clock();
cout << endl << "Runtime: " << (double)(end - start) / CLOCKS_PER_SEC << "s\n";
#endif
}
反思
再反思一次吧,希望自己端正态度,继续努力,不要气馁