Week 13
div2每日一题
目录
101. 一个小整数(回)
-
又看题解了,然后代码又没看懂、、
-
思路:任意挑数组合时:假设某个数是最多的,有maxx个,剩下的总共sum个。有4种情况。
1.maxx 大于 sum+1时,那么一定不成立,把剩下的数全插入最多的数的缝中也填不满,一定会有两个数相邻。所以该情况无法符合题意。
2.maxx 等于 sum+1时,那么只能将maxx的数两端都占有。假设有maxx个的数是x,其他的是o, 就只能 xoxoxoxox 这样排。
3.maxx 等于 sum 时,那么x只要占有一端就行,可以是:xoxoxoxoxo或者oxoxoxoxox。
4.maxx 小于 sum 时,那么就可以随意插了,只要插的时候不重复即可。
- 注意:每次插入数据之后,空位情况都会发生变化
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
const int N=100;
int v[N];
bool dfs(vector<int> &res)
{
int sum=0,maxx=0,ans=-1;
for(int i=0;i<10;i++)
{
if(v[i]>maxx) //找出最多的数
{
maxx=v[i];
ans=i;
}
sum+=v[i];
}
if(sum==0)return 1;
sum-=maxx;//剩下的数有多少个
if(maxx>sum+1)return false; //情况1
if(maxx==sum+1)//情况2,此时ans必须两端占
{
if(ans==0&&res.empty())//如果ans是数字0且res里还没存数字
{
return false;
}
else
{
res.push_back(ans);//???没看懂
v[ans]--;
}
}
else
{
int u= res.size()==0 ? 1:0;
int k= u==1 ? -1:res.back();
for(int i=u;i<10;i++)
{
if(v[i] && i!=k)
{
res.push_back(i);
v[i]--;
break;
}
}
}
return dfs(res);
}
signed main() {
int n=10;
int sum=0;
for(int i=0;i<10;i++)
{
cin>>v[i];
sum+=v[i];
}
if(v[0]==1&&sum==1)
{
cout<<"0"<<endl;
return 0;
}
vector<int>res;
if(dfs(res))
{
if(res.size()==0)cout<<-1<<endl;
else
{
for(auto x:res)
cout<<x;
cout<<endl;
}
}
else
{
cout<<"-1"<<endl;
}
return 0;
}
102. 特殊的正方形
- tips:这种上下对称的可以用char二维数组存 再分开输出。注意一下比较小的情况能不能正常输出。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
char a[105][105];
cin>>n;
for(int i=1;i<=(n+1)/2;i++)
{
int w=1;
for(int j=2;j<=i;j++)
{
if(j%2==0)
a[i][w++]='+';
else
a[i][w++]='.';
}
for(int k=1;k<=(n-2*(i-1));k++)
{
if(i%2==0)
a[i][w++]='.';
else
a[i][w++]='+';
}
for(int j=i;j>=2;j--)
{
if(j%2==0)
a[i][w++]='+';
else
a[i][w++]='.';
}
}
for(int i=1;i<=(n+1)/2;i++)
{
for(int j=1;j<=n;j++)
cout<<a[i][j];
cout<<endl;
}
if(n%2==0)
{
for(int i=1;i<=n;i++)
cout<<a[n/2][i];
cout<<endl;
}
for(int i=(n+1)/2-1;i>=1;i--)
{
for(int j=n;j>=1;j--)
cout<<a[i][j];
cout<<endl;
}
return 0;
}
103. 走楼梯2
-
还没完全学会的dp题、、注释见下
#include<bits/stdc++.h> using namespace std; long long dp[55][3]; //dp[i][j]表示的是上到第i级台阶,走了j次两级台阶 int main() { int n; cin>>n; dp[0][0]=1; for(int i=0;i<=n;i++) { for(int j=0;j<3;j++) { if(j!=2) dp[i+2][j+1]+=dp[i][j]; dp[i+1][0]+=dp[i][j]; } } cout<<dp[n][0]+dp[n][1]+dp[n][2]<<endl; return 0; }
走楼梯2 - 题目 - Daimayuan Online Judge
103 走路 (回)(dp)
-
又是dp题...没看懂题解
#include <bits/stdc++.h> #define int long long using namespace std; const int N = 1e5 + 107; bool f[103][N]; signed main() { ios::sync_with_stdio(0); cin.tie(0); int n, m; cin >> n >> m; f[0][0] = true; for (int i = 1; i <= n; i++) { int a, b; cin >> a >> b; for (int j = m; j >= min(a,b); j--) { f[i][j] |= f[i - 1][j - min(a,b)]; if (j >= max(a,b)) f[i][j] |= f[i - 1][j - max(a,b)]; } } for (int i = 0; i <= m; i++) { if (f[n][i]) cout << "1"; else cout << "0"; } }
走路 - 题目 - Daimayuan Online Judge
104 简单分数统计(map)
- tips: map容器的应用
#include<bits/stdc++.h>
using namespace std;
map<string,int> pro;
map<string,int> fri;
string peo[205];
int main()
{
int n,m,k;
cin>>n>>m>>k;
for(int i=0;i<n;i++)
cin>>peo[i];
for(int i=0;i<m;i++)
{
string s;
int x;
cin>>s>>x;
pro[s]=x;
}
for(int i=0;i<k;i++)
{
string s1,s2,s3;
cin>>s1>>s2>>s3;
if(s3=="AC")
{
fri[s1]+=pro[s2];
}
}
for(int i=0;i<n;i++)
cout<<peo[i]<<" "<<fri[peo[i]]<<endl;
return 0;
}
简单分数统计 - 题目 - Daimayuan Online Judge
105 Alice的德州扑克
- 简单的模拟判断,注意细节就行
#include<bits/stdc++.h>
using namespace std;
char ans[8][20]={"ROYAL FLUSH","STRAIGHT FLUSH", "FOUR OF A KIND","FULL HOUSE","FLUSH","STRAIGHT","FOLD"};
int flag[8],a[6],b[6];
int f=1,f2=0;
int main()
{
for(int i=0;i<5;i++)
cin>>a[i];
for(int i=0;i<5;i++)
cin>>b[i];
for(int i=0;i<4;i++)
{
if(!(a[i]+1==a[i+1]&&b[i]==b[i+1]&&a[4]==14))
flag[0]=1;
if(!(a[i]+1==a[i+1]&&b[i]==b[i+1]))
flag[1]=1;
if(a[i]==a[i+1])
{
f2=max(f2,++f);
}
else
f=1;
if(b[i]!=b[i+1])
flag[4]=1;
if(a[i]+1!=a[i+1])
flag[5]=1;
}
if(f2<4)
flag[2]=1;
if(!(f2==3&&(a[0]==a[1]||a[3]==a[4])))
flag[3]=1;
for(int i=0;i<6;i++)
{
if(!flag[i])
{
cout<<ans[i]<<endl;
return 0;
}
}
cout<<ans[6]<<endl;
return 0;
}
Alice的德州扑克 - 题目 - Daimayuan Online Judge
106 订单编号(并查集问题)(map)
-
new!并查集问题!
- 找根
int findRoot(int x) { if(mp[x]!=x) mp[x]=findRoot(mp[x]); return mp[x]; }
-
合并
void unionTree(int a,int b) { int x=findRoot(a); int y=findRoot(b);//在执行findRoot的时候就已经把b的值变成它的根的值了 if(x==y) return; if(x>y) swap(x,y);//让大的还是让小的为根可以根据题目决定 mp[x]=y; return ; }
-
关于map
- 查找时unordered_map会比较快,这题用map会超时
- count(x): 找到返回1,找不到返回0。注意count找的是key值!
- 另:find(x)中的x也是key值,找不到返回mp.end()。
-
本题思路:把出现过的数字并在一堆,根为这一堆里最大的数字+1(即重复出现这堆数字中的数时应该取的数字),用ans存最后的答案输出即可
#include<bits/stdc++.h> using namespace std; const int N=1e6+10; int ans[N],a[N]; int n; unordered_map<int,int> mp; int findRoot(int x) { if(mp[x]!=x) mp[x]=findRoot(mp[x]); return mp[x]; } void unionTree(int a,int b) { int x=findRoot(a); int y=findRoot(b);//在执行findRoot的时候就已经把b的值变成它的根的值了 if(x==y) return; if(x>y) swap(x,y);//这题让大的为根 mp[x]=y; return ; } int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; mp[a[i]]=a[i]; } for(int i=1;i<=n;i++) { int now=a[i]; int root=findRoot(a[i]); if(now==root) //如果这个数字还没被使用过 { ans[i]=now; if(mp.count(now+1)==0) mp[now+1]=now+1;//如果比这个数字大一的数字还没有使用过 unionTree(now,now+1);//并进去作为这个的根 } else //如果这个数字已经使用过 { ans[i]= root; if(mp.count(root+1)==0) mp[root+1]=root+1; unionTree(root,root+1); } } for(int i=1;i<=n;i++) cout<<ans[i]<<" "; return 0; }
订单编号 - 题目 - Daimayuan Online Judge
107 饿饿 饭饭
-
二分答案题
-
思路:二分法,check轮数x,找到最后一轮的情况,然后模拟一下队列
-
注意:
- 注意数据规模,k能到10的14次方
(谁家阿姨打饭能打这么多次啊),要用long long - 如果是从1开始存
(平时习惯从0开始存的,今天一时兴起从1存然后掉入坑里orz),最后遍历的时候,如果刚好等于n,取余结果是会为0的...也就是a[n]被略过了,特判一下吧
- 注意数据规模,k能到10的14次方
-
最后一个测试点超时了,很崩溃,试着用map存了一次删除出队的数据,but失败了,##肝不动了我选择摆烂
#include<bits/stdc++.h> using namespace std; const long long N=1e5+10; long long n,k,ans=-2,sum=0; long long a[N]; long long check(int x) { long long s=0; //s表示的是x轮吃掉的饭的数量 for(long long i=1;i<=n;i++) { if(a[i]<x) s+=a[i]; else s+=x; } if(k-s>=0) return (k-s); //返回阿姨还应该打的饭的数量 else return -1; } int main() { cin>>n>>k; for(long long i=1;i<=n;i++) { cin>>a[i]; sum+=a[i]; } if(sum<k) { cout<<"-1"<<endl; return 0; } else if (sum==k) { return 0; } else { long long l=0,r=k,t; while(l<=r) { long long mid=l+(r-l)/2; //表示轮多少圈 if(check(mid)!=-1) { t=check(mid); ans=mid; l=mid+1; } else r=mid-1; } for(long long i=1;i<=n;i++) { if(a[i]<=ans) a[i]=0; else a[i]-=ans; } long long i=1; while(1) { if(t==0) break; if(a[i]!=0) { t--; a[i]--; } i++; if(i==n+1) i=1; } for(long long j=0;j<n;j++) { if((i+j)%n==0&&a[n]!=0) cout<<n<<" "; if(a[(i+j)%n]!=0) cout<<(i+j)%n<<" "; } } return 0; }
108 任务分配(回)(dp)
-
状态转移方程依然没看懂、、这周必把dp刷会
#include<bits/stdc++.h> #define ll long long using namespace std; int dp[1004]; struct node { int l,r,w; }ms[1004]; bool cmp(node a,node b){ if(a.r == b.r) return a.l > b.l; return a.r < b.r; } int main(){ int n; cin >> n; for(int i = 1; i <= n; i++){ cin >> ms[i].l >> ms[i].r >> ms[i].w; } sort(ms + 1,ms + 1 + n,cmp); for(int i = 1; i <= n; i++){ for(int j = 1; j <= ms[i].l; j++){ dp[j] = max(dp[j],dp[j - 1]); if(j == ms[i].l){ dp[ms[i].r] = max(dp[ms[i].l] + ms[i].w,dp[ms[i].r]); } } } int maxn = 0; for(int j = 1; j <= 1000; j++){ maxn = max(dp[j],maxn); } cout << maxn << '\n'; return 0; }
洛谷dp题
- 试图苦练dp然后刚刚入门、、
P1216 数字三角形 Number Triangles
- dp入门,求路径数字和最大
#include<bits/stdc++.h>
using namespace std;
int dp[1005][1005];//dp[i][j]表示以第i行第j列为终点的最大值
int a[1005][1005];
int ma;
int main()
{
int r;
cin>>r;
for(int i=1;i<=r;i++)
{
for(int j=1;j<=i;j++)
{
cin>>a[i][j];
}
dp[i][1]=a[i][1]+dp[i-1][1];
}
for(int i=2;i<=r;i++)
{
for(int j=2;j<=i;j++)
{
dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+a[i][j];
if(i==r)
{
ma=max(dp[i][j],ma);
}
}
}
cout<<ma<<endl;
return 0;
}
- 滚动数组优化
dp[1]=a[1][1];
for(int i=2;i<=r;i++)
{
for(int j=i;j>=2;j--) //从后往前,不然会被覆盖
{
dp[j]=max(dp[j-1],dp[j])+a[i][j];
if(i==r)
{
ma=max(dp[j],ma);
}
}
dp[1]+=a[i][1]; //更新dp[1]
}
P2196 挖地雷
- 对存路径有点迷茫TAT,看了俩小时
- 注意不能有多余空格不然只有60分
#include<bits/stdc++.h>
using namespace std;
int a[25],dp[25],path[25][25],p[25];
//dp[i]表示以i为终点地雷最多的路
//p[i]表示最优路径下i的前驱 后续输出路径
int n,maxn,maxi;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
dp[i]=a[i];//初始化
}
for(int i=1;i<n;i++)
{
for(int j=i+1;j<=n;j++)
{
cin>>path[i][j]; //表示i能否通向j
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)//important!因为路是单向的,前面输入的路径是第i号地窖往后通,所以这里应该看第i号地窖往前有没有别的地窖通向i
{
if(path[j][i]!=0&&dp[i]<dp[j]+a[i]) //j能通向i
{
dp[i]=dp[j]+a[i];
p[i]=j;
}
}
if(dp[i]>maxn)
{
// cout<<dp[i]<<endl;
maxn=dp[i];
maxi=i;
}
}
stack<int> s;
while(maxi)
{
s.push(maxi);
maxi=p[maxi];
}
cout<<s.top();
s.pop();
while(!s.empty())
{
cout<<" "<<s.top();
s.pop();
}
cout<<endl;
cout<<maxn<<endl;
return 0;
}
P1060 开心的金明
-
01背包问题
#include<bits/stdc++.h> using namespace std; const int N=30010; int w[N],v[N],dp[N]; int m,n; int main() { cin>>n>>m; for(int i=1;i<=m;i++) cin>>v[i]>>w[i]; for(int i=1;i<=m;i++) { for(int j=n;j>=1;j--) { if(j>=v[i]) dp[j]=max(dp[j],dp[j-v[i]]+v[i]*w[i]); } } cout<<dp[n]<<endl; return 0; }
P8697 [蓝桥杯 2019 国C] 最长子序列
-
感觉不太对劲,题目说用dp但是我很简单就过掉了(?
#include<bits/stdc++.h> using namespace std; string s1,s2; int ans,len1,len2; int main() { cin>>s1>>s2; len1=s1.length(); len2=s2.length(); for(int i=0;i<len1;i++) { if(s1[i]==s2[ans]) { ans++; } } cout<<ans<<endl; return 0; }
P8707 [蓝桥杯 2020 省 AB1] 走方格
- dp基础题捏,求到某个格子最多多少条路
#include<bits/stdc++.h>
using namespace std;
int m,n;
int dp[35][35];//到第i行第j列有多少条路
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
dp[1][i]=1;
for(int i=1;i<=n;i++)
dp[i][1]=1;
for(int i=2;i<=n;i++)
{
for(int j=2;j<=m;j++)
{
if(i%2!=0||j%2!=0)
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
cout<<dp[n][m]<<endl;
return 0;
}
P1802 5倍经验日
- 01背包问题
- 注意:两个测试点没过
- 最后结果很大应该开long long
- 注意数据范围,药水数量x是可以为0的!!也有不用药水就能打败的敌人!
#include<bits/stdc++.h>
using namespace std;
int n,x;
long long lose[1010],win[1010],use[1010],dp[1010][1010];
int main()
{
cin>>n>>x;
for(int i=1;i<=n;i++)
{
cin>>lose[i]>>win[i]>>use[i];
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=x;j++)
{
if(j>=use[i])
dp[i][j]=max(dp[i-1][j],dp[i-1][j-use[i]]+win[i]);
dp[i][j]=max(dp[i][j],dp[i-1][j]+lose[i]);
}
}
cout<<5*dp[n][x]<<endl;
return 0;
}
P1434 [SHOI2002] 滑雪
- dfs+记忆化搜索
#include<bits/stdc++.h>
using namespace std;
int r,c,ans;
int mp[105][105],dp[105][105];//dp[i][j]表示从i j出发的最长道路是多少
int xx[5]={0,1,0,-1};
int yy[5]={-1,0,1,0};
int dfs(int x,int y)
{
if(dp[x][y]) return dp[x][y];//记忆化搜索
dp[x][y]=1;
for(int i=0;i<4;i++)
{
int nx=x+xx[i];
int ny=y+yy[i];
if(nx>=1&&nx<=r&&ny>=1&&ny<=c&&mp[x][y]>mp[nx][ny])
{
dfs(nx,ny);
dp[x][y]=max(dp[x][y],dp[nx][ny]+1);
}
}
return dp[x][y];
}
int main()
{
cin>>r>>c;
for(int i=1;i<=r;i++)
{
for(int j=1;j<=c;j++)
{
cin>>mp[i][j];
}
}
for(int i=1;i<=r;i++)
{
for(int j=1;j<=c;j++)
{
ans=max(ans,dfs(i,j));
}
}
cout<<ans<<endl;
return 0;
}