- 赵一静 的博客
八月暑期集训8月5日DAY1题解
- @ 2024-8-5 17:11:41
数字统计(模拟)
思路
没有什么好讲的,纯纯模拟,记得数位分离。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
freopen("tj.in","r",stdin);
freopen("tj.out","w",stdout);
int l,r;
int cnt=0;
cin >>l>>r;
for(int i=l;i<=r;i++){
int res=i;
while(res){
if(res%10==2) cnt++;
res=(res-(res%10))/10;
}
}
cout <<cnt;
return 0;
}
乒乓球(模拟)
思路没想到的原因
数组开小了,以后注意数据范围。
思路
直接模拟,满足条件就放入数组里。最后输出注意格式。
代码
#include <bits/stdc++.h>
using namespace std;
const int tt=1e6+10;
int a[tt],b[tt],c[tt],d[tt];
int main(){
freopen("pingpong.in","r",stdin);
freopen("pingpong.out","w",stdout);
char z;
int i=1;
int j=1;
int cnt=0;
for(;;cnt++){
cin >>z;
if(z=='E'){
break;
}else{
if(z=='W'){
a[i]++;
c[j]++;
}else{
b[i]++;
d[j]++;
}
if((a[i]>=11||b[i]>=11)&&(a[i]-b[i]>=2||b[i]-a[i]>=2)){
i++;
}
if((c[j]>=21||d[j]>=21)&&(c[j]-d[j]>=2||d[j]-c[j]>=2)){
j++;
}
}
}
for(int k=1;k<=i;k++){
cout <<a[k]<<":"<<b[k]<<endl;
}
cout <<endl;
for(int k=1;k<=j;k++){
cout <<c[k]<<":"<<d[k]<<endl;
}
return 0;
}
侦探推理(模拟)
思路没想到的原因
模拟的能力还需加强,一遇到大模拟就不会写。
思路
本题是一个超~~~~~~大的模拟!!!
将证词和人分开处理,更简单直接。可以用map将对字符串的处理转为对数的处理,进一步简化代码。
将证词分成说是凶手,说不是凶手,说今天是星期几。
每句证词都可分为真话和假话,关于凶手和星期,共有四类,直接用基本的循环就可以了。
接着枚举可能的星期和凶手,判断是否可行。
需注意判断函数。
代码
#include <bits/stdc++.h>
using namespace std;
string mz[110];
int state[110],fh=0,hh=0;
bool st[110];
pair<int,string>zc[110];
int m,n,p;
string week[]={
"Today is Monday.",
"Today is Tuesday.",
"Today is Wednesday.",
"Today is Thursday.",
"Today is Friday.",
"Today is Saturday.",
"Today is Sunday."
};
int get_id(string s){
for(int i=1;i<=m;i++){
if(s==mz[i]) return i;
}
return -1;
}
int judge(int day,int bad,int now,string s){
if(s=="I am guilty.") return now!=bad;
if(s=="I am not guilty.") return now==bad;
for(int i=1;i<=m;i++){
if(s==mz[i]+" is guilty."){
return i!=bad;
}
}
for(int i=1;i<=m;i++){
if(s==mz[i]+" is not guilty."){
return i==bad;
}
}
for(int i=0;i<7;i++){
if(s==week[i]) return i!=day;
}
return -1;
}
bool check(int day,int bad){
fh=hh=0;
memset(state,-1,sizeof state);
for(int i=1;i<=p;i++){
if(judge(day,bad,zc[i].first,zc[i].second)==1){
if(state[zc[i].first]==-1) state[zc[i].first]=1;
if(state[zc[i].first]==0) return false;
}else if(judge(day,bad,zc[i].first,zc[i].second)==0){
if(state[zc[i].first]==-1) state[zc[i].first]=0;
if(state[zc[i].first]==1) return false;
}
}
for(int i=1;i<=m;i++){
if(state[i]==1) hh++;
else if(state[i]==-1) fh++;
}
return hh<=n&&n<=hh+fh;
}
int main(){
freopen("zt.in","r",stdin);
freopen("zt.out","w",stdout);
int cnt=0;
string op="";
cin >>m>>n>>p;
for(int i=1;i<=m;i++){
cin >>mz[i];
}
for(int i=1;i<=p;i++){
string first,second;
cin >>first;
first.erase(first.end()-1);
getline(cin,second);
second.erase(second.begin());
zc[i]={get_id(first),second};
}
for(int i=1;i<=m;i++){
for(int day=0;day<7;day++){
if(check(day,i)&&st[i]==0){
cnt++;
op=mz[i];
st[i]=1;
}
}
}
if(cnt>1){
cout <<"Cannot Determine";
}else if(cnt==1){
cout <<op;
}else{
cout <<"Impossible";
}
return 0;
}
游戏(DP&前缀和)
思路没想到的原因
没有转化一些看似很复杂的题面部分,下次应该将复杂的题面联系到自己学过的知识并加以运用。
思路
因为输入的数据是一个环,所以我们要破环为链。怎样破环为链呢?很简单,在输入的时候复制一遍在数组后面:a[i+n]=a[i]。这样问题就转化成了线段型的模型。
状态表示:
- 表示所有将分割成部分的方案的最大乘积;
- 表示所有将分割成部分的方案的最小乘积。
- 表示数组的前缀和。
状态计算:
$f[l][r][k]=max(f[l][r][k],f[l][t-1][k-1]*op(s[r]-s[t-1]))$ $g[l][r][k]=min(g[l][r][k],g[l][t-1][k-1]*op(s[r]-s[t-1]))$
还有要记得避免负数的情况,可以用一个函数来写,简洁明了。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int tt=110;
int a[tt],f[tt][tt][tt],s[tt*2],g[tt][tt][tt];
int op(int n){
while(n<0) n+=10;
return n%10;
}
signed main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
memset(g,0x2f2f2f2f,sizeof g);
int n,m;
cin >>n>>m;
for(int i=1;i<=n;i++){
cin >>a[i];
a[i+n]=a[i];
}
for(int i=1;i<=n*2;i++){
s[i]=s[i-1]+a[i];
}
for(int len=1;len<=n;len++){
for(int l=1;l<=n+1;l++){
int r=l+len-1;
f[l][r][1]=op(s[r]-s[l-1]);
g[l][r][1]=op(s[r]-s[l-1]);
for(int k=2;k<=m;k++){
for(int t=l+1;t<r;t++){
f[l][r][k]=max(f[l][r][k],f[l][t-1][k-1]*op(s[r]-s[t-1]));
g[l][r][k]=min(g[l][r][k],g[l][t-1][k-1]*op(s[r]-s[t-1]));
}
}
}
}
int max_n=0,min_n=0x2f2f2f2f;
for(int i=1;i<=n+1;i++){
max_n=max(f[i][i+n-1][m],max_n);
min_n=max(min(g[i][i+n-1][m],min_n),0ll);
}
cout <<min_n<<endl<<max_n;
return 0;
}