觉得还是得每周记录一下刷过的题,分析题目和做题思路,对近期学习阶段总结一下。
记录原则,当时存在的问题,和题目正确的思路
目录
南华校赛:
简单搜索签到
马走日直接八个方向遍历就出来了,因为题目要求点在1,1以上,边界没有continue好,在垃圾编译环境下debug半天,而且贡献了一发ce 555,所以不仅要会板子,还得根据题目实事求是。
抽卡
规律题,队友打表写的,多列出几项发现就是2的n次方
挖隧道安全版
思路如上,dp在于状态选择,状态划分,最后状态转移
void solved()
{
d[1][0]=a[1];//前1次,当前不炸的最大价值
d[1][1]=60;//前1次,当前炸的最大价值
for(int i=2;i<=n;i++){
d[i][0]=min(d[i-1][0],d[i-1][1])+a[i];
d[i][1]=min(d[i-1][0]+60,d[i][1]);//直接min不用分类讨论
if(i>=3)//第1次转移到第三次
d[i][1]=min(d[i-3][0]+150,d[i][1]);
}
Baimuii的双向队列
问题最难处理是怎么每次只操作一小段并且送回去,一开始跟队友一起模拟字符串改位置,debug烂了,没时间也没那么多精力
正解:利用string容器,要处理区间长度,写cin>>str,str=" "+str;方便处理区间
substr提取k%len(修改区间的长度)实现优化,再用replace将修改后的字符串送回去
int main() {
cin >> str >> m;
str = " " + str;
while (m--) {
string op;
long long l, r, k;
cin >> op;
if (op == "R") {
cin >> l >> r >> k;
int len = r - l + 1;
k %= len;
if (k == 0)
continue;
string s1, s2;
s1 = str.substr(l + len - k, k), s2 = str.substr(l, len - k);
str.replace(l, k, s1), str.replace(l + k, len - k, s2);
} else if (op == "L") {
cin >> l >> r >> k;
int len = r - l + 1;
k %= len;
if (k == 0)
continue;
string s1, s2;
s1 = str.substr(l, k), s2 = str.substr(l + k, len - k);
str.replace(l + len - k, k, s1), str.replace(l, len - k, s2);
} else {
for (int i = 1; i < str.size(); i++) {
cout << str[i];
}
puts("");
}
}
return 0;
}
第四届SCPC中南民族大学
Funny哥卖锅盔
栈模拟吧,没看到数据保证m小于n,即不会出现需要重新遍历原串的情况,不知道自己写的模拟循环在哪里超时了。。。
正解:while(1)和if continue顺序是没问题的,自己模拟只过了86%的数据,这种时候就要加代码强行排除情况,比如在出栈操作后,加i指针越界break,判断栈的状态
void solved()
{
cin>>n>>m>>s1>>s2;
stack<char> st;
if(strlen(s1)==strlen(s2))
{
len=strlen(s2);
while(1)
{
if(!st.empty()&&st.top()==s2[j])
{ st.pop(),j++;continue;}
if(i>=len)break;
if(s2[j]==s1[i])
{i++,j++;continue;}
if(st.size()<m)
{st.push(s1[i]),i++;continue;}
printf("That's not Funny at all!\n");
return;
}
}
else{
printf("That's not Funny at all!\n");return;
}
if(st.empty())printf("Don't you think that's Funny?\n");
else {
printf("That's not Funny at all!\n");
}
;
}
阿毛与王爷
异或题,发现很多异或都是找二进制规律,自己独立写的时候没考虑到1多的情况,以为直接0。
正解:保证1的个数必须为n,那么很简单考虑大于1改0算二进制,等于为0,小于0改1算二进制,保证数据小于X
void solved()
{
int n,x;cin>>n>>x;
int a=0,b=0;
for(int i=0;i<31;i++)
if(x>>i&1)a++;
else b++;
int y=0;
if(a==n)printf("Piaoliangdehenna!\n%d\n",0);
else if(a<n)
{
int res=0;
int cnt=n-a;
//cout<<a<<endl;
//cout<<cnt<<endl;
for(int i=0;i<31&&cnt;i++)
if(x>>i&1);
else res+=pow(2,i),cnt--;
if(res<=x)printf("Piaoliangdehenna!\n%d\n",res);
else puts("Chuola!");
}
else{
int res=0;
for(int i=0;i<31&&a!=n;i++)
if(x>>i&1)res+=1<<i,a--;
if(res<=x)printf("Piaoliangdehenna!\n%d\n",res);
else puts("Chuola!");
}
;
}
一个人挺好
构造类题目,只要保证符合题意构造,不需要和样例一模一样,一般就是思维找规律
正解:剩余101010如此,该串后面补多出来对数>>1的0即可
void solved()
{
int n,m;cin>>n>>m;
if((m-n)%2==1)puts("-1");
else {
int cnt=m-n;
for(int i=1;i<=n;i++)
cout<<(i%2==1)?1:0;
while(cnt--)
cout<<0;
puts("");
}
;
}
啵啵小狗自动机(easy version)
打表题,sb了,手打表验证没问题,打数据确实有点牛马,尽量代码实现吧
正解:找到较大的个数下(i+1方-i方大于100)i>99/2都可以,把答案标记一下就可以了
bool st[1000];
int main()
{
for(int i=1;i<=50;i++)
for(int j=i+1;j<=50;j++)
if(j*j-i*i<=100)st[j*j-i*i]=1;
int n;cin>>n;
puts(st[n]?"YES":"NO");
}
南湖的瓜
队友写的,看了下题感觉就是floodfill统计连通块取个数最大的俩个连通块
正解:就是这个思路
发现问题,还是根据题目意思,一般尽量用st判断来bfs,因为不能走同样的路
char g[N][N];
int n, m;
int dx[] = { 0,1,0,-1 }, dy[] = { 1,0,-1,0 };
bool st[N][N];
bool cmp(int x,int y)
{
return x>y;
}
int bfs(int x, int y)
{
int cnt = 1;
queue<PII> q;
q.push({ x,y });
st[x][y]=1;
g[x][y]='.';
while (q.size())
{
auto t = q.front(); q.pop();
for (int i = 0; i < 4; i++)
{
int xx = t.first + dx[i], yy = t.second + dy[i];
if (xx < 0 || xx >= n || yy < 0 || yy >= m || g[xx][yy] == '#'||st[xx][yy])continue;
if(g[xx][yy]=='*')cnt++;
q.push({ xx,yy });
g[xx][yy]='.';
st[xx][yy]=1;
// printf("%d %d %d\n",xx,yy,cnt);
}
}
return cnt;
}
void solved()
{
cin >> n >> m;
for (int i = 0; i < n; i++)cin >> g[i];
vector<int> res;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
if (g[i][j] == '*')
res.pb(bfs(i, j));
}
// for(auto x:res)cout<<x<<endl;
sort(res.begin(), res.end(),cmp);
if(res.size()==1)cout<<res[0]<<"\n";
else
printf("%d\n", res[0] + res[1]);
}
雨声里的相遇
自己写的时候奇数偶数长度的性质判断没处理好,没有过全部数据
正解:十进制转n进制,回文字符串,前一半必须严格上升,
判断顺序回文中,注意偶数要多--,奇数取原长度比2就行了
char mp[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G',
'H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X',
'Y','Z'};
bool check(string s)
{
for(int i=0,j=s.size()-1;i<s.size()/2;i++,j--)
if(s[i]!=s[j])return false;
return true;
}
void solved()
{
int n,s;cin>>n>>s;
/* for(int i=0;i<36;i++)
{
if(i<10)printf("'%d',",i);
else if(i<36)
printf("'%c',",i-10+'A');
}*/
;
bool ok=0;
for(int i=2;i<=n;i++)
{
int tmp=s;
string res;
while(tmp)
{
res+=mp[tmp%i];
tmp/=i;
}
bool flag=1;
if(check(res))
{
int len=res.size()/2;
if(res.size()%2==0)len--;
for(int i=0;i<len;i++)
{
if(res[i]>=res[i+1]){flag=0;break;}
}
if(flag)
{
ok=1;
printf("%d ",i);
cout<<res<<"\n";
}
}
}
if(!ok)puts("guomienasai");
}
花海
自己有思路,很难实现
正解:向量叉乘,给出o点,求每个三角如oab,求和矢量性质,包括首尾,
Soab==x1*y2-x2*y1
struct node
{
int x,y;
}q[N];
void solved()
{
int n;cin>>n;
for(int i=0;i<n;i++)
cin>>q[i].x>>q[i].y;
q[n].x=q[0].x,q[n].y=q[0].y;
double res=0;
for(int i=0;i<n;i++)
{
res+=q[i].x*q[i+1].y-q[i].y*q[i+1].x;
}
res/=2;
printf("%.3lf\n",fabs(res));
;
}
啵啵小狗自动机(hard version)
数据量变大,不再可以模拟打记录,观察打出来的多组数据,发现(i+1)^2-i^2一定是奇数或者被4整除
南湖的瓜-续
输出一组符合题意得案例,直接特殊值0就能过