第一题 一个小整数
题面http://oj.daimayuan.top/problem/1002
思路,最开始想的是先找出最多的数和其他数总和,如果最多的数大,则必有相邻重复项,如果小,再先由小到大不重复的排,排完之后在倒序插入剩下的数,但后来发现如果 8,9 有很多,8会和7匹配,剩9,就变成78787878插9,就成了789789798,但很明显,正确答案应该是78787898989,
后来,改成了
我们的目的是每次选尽可能小且不重复的数,同时要保证有解,不能出现1212999这种情况,所以假设前面选的数符合题意,我们只要保证接下来的数最小就解出来了,sum为其他数总和,max为最多数的个数。
sum=0;
数选完了,返回1
sum+1=max
只有xyxyx这一种排法,所以只能选最多的那个数
sum+1>max
保证不重复的选一个最小的数就行了
最后0要单独拧出来,同时初始last=0,保证首项不为0;
#include<bits/stdc++.h>
using namespace std;
vector<int>ans;
int last=0;
int num[10];
bool dfs(){
int sum=0;int maxx=0; int maxn=0;
//maxx记录最大数的个数,maxn记录最大数
for(int i=0;i<10;i++){
if(num[i]>maxx){
maxx=num[i];
maxn=i;
}
sum+=num[i];
}
if(sum==0)return 1;
sum-=maxx;
if(sum+1<maxx){return 0;}
if(sum+1==maxx){
if(maxn==0&&ans.empty()){
return 0;
}
ans.push_back(maxn);
num[maxn]--;
last=maxn;
}else{
for(int i=ans.size()==0?1:0;i<10;i++){
if(i!=last&&num[i]){
ans.push_back(i);
num[i]--;
last=i;
break;
}
}
}
return dfs();
}
int main(){
int sum=0;
for(int i=0;i<10;i++){
cin>>num[i];
sum+=num[i];
}
if(sum==1&&num[0]){
cout<<0;
return 0;
}
if(dfs()){
if(ans.size()==0){
cout<<-1;
}else{
for(auto a:ans){
cout<<a;
}
}
}else{
cout<<-1;
}
//cout<<endl;
// for(auto x:num){
// cout<<x<<endl;
// }
}
第二题 特殊的正方形
题面http://oj.daimayuan.top/course/11/problem/386
由正方形,所以我们只要排出左上角的一小块就行了,之后在根据奇偶镜像打印输出
对于每一个点,若他上和左的一样,则这个点和这两不一样
若上和左不一样,但上和左上一样,则他和左一样
若上和左不一样,但左和左上一样,则他和上一样
#include<bits/stdc++.h>
using namespace std;
int n;
bool ans[55][110]={0};
int main(){
cin>>n;
for(int i=0;i<n/2+1;i++){
for(int j=0;j<n;j++){
if(i==0){
ans[i][j]=1;
continue;
}
if(j==0){
ans[i][j]=1;
continue;
}
if(ans[i-1][j]==ans[i][j-1]){
ans[i][j]=(!ans[i][j-1]);
}else if(ans[i-1][j-1]==ans[i-1][j]){
ans[i][j]=ans[i][j-1];
}else{
ans[i][j]=ans[i-1][j];
}
}
}
// for(int i=0;i<n/2+1;i++){
// for(int j=0;j<n;j++){
// cout<<ans[i][j];
// }
// cout<<endl;
// }
if(n%2==0){
for(int i=0;i<n/2;i++){
for(int j=0;j<n/2;j++){
if(ans[i][j]){
cout<<"+";
}else{
cout<<".";
}
}
for(int j=n/2-1;j>=0;j--){
if(ans[i][j]){
cout<<"+";
}else{
cout<<".";
}
}
cout<<endl;
}
for(int i=n/2-1;i>=0;i--){
for(int j=0;j<n/2;j++){
if(ans[i][j]){
cout<<"+";
}else{
cout<<".";
}
}
for(int j=n/2-1;j>=0;j--){
if(ans[i][j]){
cout<<"+";
}else{
cout<<".";
}
}
cout<<endl;
}
}else{
for(int i=0;i<n/2+1;i++){
for(int j=0;j<n/2+1;j++){
if(ans[i][j]){
cout<<"+";
}else{
cout<<".";
}
}
for(int j=n/2-1;j>=0;j--){
if(ans[i][j]){
cout<<"+";
}else{
cout<<".";
}
}
cout<<endl;
}
for(int i=n/2-1;i>=0;i--){
for(int j=0;j<n/2+1;j++){
if(ans[i][j]){
cout<<"+";
}else{
cout<<".";
}
}
for(int j=n/2-1;j>=0;j--){
if(ans[i][j]){
cout<<"+";
}else{
cout<<".";
}
}
cout<<endl;
}
}
}
第三题 走楼梯2
题面http://oj.daimayuan.top/course/11/problem/129
最开始想的是dp,就第n阶等于n-1的情况跨一步和n-2的跨两步,之后以为n-2只有一种情况会到n-2有连跨两次两步,就只减了1,后面发现远不止一种情况
对于第n个台阶,两种跳法,1,从n-1跳一步,2从n-2跳两步,但要排除掉连跳三次的,3,从n-6开始可以连跳三次到n,但不是所有n-6的情况都能连跳,只有跳一步到n-6的才能连跳,所以减掉n-7就行了
最后发现45都能过,50过不了,调了半天发现,没开longlong。。。。。
#include<bits/stdc++.h>
using namespace std;
long long ans[55];
int n;
int main(){
cin>>n;
ans[0]=1;
ans[1]=2;
ans[2]=3;
ans[3]=5;
ans[4]=8;
ans[5]=12;
ans[6]=19;
ans[7]=30;
if(n<7){
cout<<ans[n-1];
return 0;
};
for(int i=8;i<n;i++){
ans[i]=ans[i-1]+ans[i-2]-ans[i-7];
}
cout<<ans[n-1];
return 0;
}
第四题
题面http://oj.daimayuan.top/course/11/problem/460
第一次用dfs写,不出意外的TLE了,于是转成动规
dp[i][j]表示第i行的第j位置能不能跑到
于是 dp[i][j]=(dp[i-1][j-ori[i][0]]||dp[i-1][j-ori[i][1]]);
然后第一行在手输一下就完事
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int dp[110][maxn]={0};
int ori[110][2];
int n,m;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>ori[i][0];
cin>>ori[i][1];
}
dp[1][ori[1][0]]=1;
dp[1][ori[1][1]]=1;
for(int i=2;i<=n;i++){
for(int j=0;j<=m;j++){
dp[i][j]=(dp[i-1][j-ori[i][0]]||dp[i-1][j-ori[i][1]]);
}
}
for(int i=0;i<=m;i++){
cout<<dp[n][i];
}
}
第五题 简单分数统计
题面:http://oj.daimayuan.top/problem/455
很水的水题,,,,用map优化了一下,感觉写的还是不行,也许能优化,但,没必要,哎嘿。
#include <bits/stdc++.h>
using namespace std;
int main() {
map<string, int>ori;
int n, m, k;
cin >> n >> m >> k;
string name1[210];
for (int i = 1; i <= n; i++) {
string a;
cin >> a;
ori[a] = i;
name1[i] = a;
}
map<string, int > ti;
for (int i = 0; i < m; i++) {
string temp;
int temp1;
cin >> temp >> temp1;
ti[temp] = temp1;
}
int score[210] = { 0 };
for (int i = 0; i < k; i++) {
string name, timu, pass;
cin >> name >> timu >> pass;
if (pass == "WA")continue;
if (ori[name] == 0)continue;
score[ori[name]] += ti[timu];
}
for (int i = 1; i <= n; i++) {
cout << name1[i] << " " << score[i] << endl;
}
}
第六题 Alice的德州扑克
题面:http://oj.daimayuan.top/problem/453
水题+1
#include<bits/stdc++.h>
using namespace std;
struct pai
{
int dian;
int hua;
};
pai ori[5];
int dian[15];
int main(){
for(int i=0;i<5;i++){
cin>>ori[i].dian;
dian[ori[i].dian]++;
}
for(int i=0;i<5;i++){
cin>>ori[i].hua;
}
bool shun=1;
for(int i=1;i<5;i++){
if(ori[i].dian!=(ori[i-1].dian+1)){
shun=0;
break;
}
}
bool tong =1;
for(int i=1;i<5;i++){
if(ori[i].hua!=ori[i-1].hua){
tong=0;
break;
}
}
if(shun==1&&tong==1&&ori[4].dian==14){
cout<<"ROYAL FLUSH"<<endl;
return 0;
}
if(shun==1&&tong==1){
cout<<"STRAIGHT FLUSH"<<endl;
return 0;
}
for(int i=1;i<=14;i++){
if(dian[i]>=4){
cout<< "FOUR OF A KIND"<<endl;
return 0;
}
}
int fullhouse1=0;
int fullhouse2=0;
for(int i=1;i<=14;i++){
if(dian[i]>=3){
fullhouse1++;
}
if(dian[i]==2){
fullhouse2++;
}
}
if(fullhouse1==1&&fullhouse2==1){
cout<<"FULL HOUSE"<<endl;
return 0;
}
if(tong==1){
cout<< "FLUSH"<<endl;
return 0;
}
if(shun==1){
cout<<"STRAIGHT"<<endl;
return 0;
}
cout<<"FOLD"<<endl;
}
第七题 订单编号
题面:http://oj.daimayuan.top/problem/465
最开始写了个dp优化的累加,若有相同的数则从dp里面找最大,但还是卡了一个点,最后改成:
用set存所有有空位的区间,当处理一个数x的时候,找到离他最近的右端比他大的区间,如果找左端的话会出现区间[4,6],[8,10];找6,会返回[8,10],而我们要找的是[4,6],之后根据找到的区间的左端选择输出x还是右端,输出完后更新区间即可
一些细节写在注释里了
由于是查的区间,效率会比dp的一个数一个数的找快
#include<bits/stdc++.h>
using namespace std;
set<pair<int,int>> qujian;
//pair 第一个为右端,第二个为左端
void join(int r,int l){
if(l>r)return;
qujian.insert({r,l});
//second x-1 x x+1 first
//x+1有可能比first大,同理x-1所以要判断
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
qujian.insert({2e9,1});
int x;
for(int i=0;i<n;i++){
cin>>x;
auto it=qujian.lower_bound({x,0});
//查找比[0,x]右端大的第一个区间,因为小于x的区间都用不了
//second是左,first是右端
if(x>=it->second){
cout<<x<<" ";
join(it->first,x+1);
join(x-1,it->second);
qujian.erase(it);
//左端小于x,输出x
//second x-1 x x+1 first
}else{
cout<<it->second<<" ";
join(it->first,it->second+1);
qujian.erase(it);
//左端大于x,输出左端
}
//cout<<0;
}
}
第八题463. 饿饿 饭饭
用优先队列存饭量,每次喂给所有人饭量最小的分量,也就是喂了最小分量的轮数,同时k减少轮数*人数,当不能在喂一轮后,start=k%人数,之后从start开始,判断能不能喂饱,能就跳过
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
struct ren {
int fan;
int id;
friend bool operator < (ren a, ren b) {
return a.fan > b.fan;
}
};
int ori[maxn];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
long long k;
cin >> n >> k;
priority_queue<ren> shu;
long long sum = 0;
for (int i = 1; i <= n; i++) {
ren temp;
cin>>temp.fan;
//temp.fan = i;
temp.id = i;
shu.push(temp);
sum += temp.fan;
ori[i] = temp.fan;
}
if (sum < k) {
cout << -1;
return 0;
}
if (sum == k) {
return 0;
}
ren top;
int lun = 0;
int start;
int last;
while (!shu.empty())
{
top = shu.top();
if (k <(shu.size() * (top.fan-lun))) {
//不满足再打一轮
start=k%shu.size();
last=(k-start)/shu.size();
break;
}
lun+=top.fan;
k -= shu.size()*lun;
//cout << lun << endl;
while (top.fan == shu.top().fan)
{
shu.pop();
}
}
int ans[maxn];
int answei = 0;
while (!shu.empty())
{
ren temp;
temp = shu.top();
shu.pop();
ans[answei++] = temp.id;
}
sort(ans, ans + answei);
for (int i = start; i < answei; i++) {
//最后一轮没吃到饭的
cout << ans[i] << " ";
}
for (int i = 0; i < start; i++) {
if (ori[ans[i]] == lun + last+1)continue;
cout << ans[i] << " ";
}
return 0;
}
第九题 任务分配
题面 http://oj.daimayuan.top/course/11/problem/461
第一种,纯纯暴力
dp[i]代表i时的最大值
每一个时刻都转一遍所有计划,如果有计划的起始等于i,更新计划的终点,终点等于终点原先的时刻价值和起始点加价值后两者的最大值,
两个细节
1,只有时刻过了终点后最大值才会更新
2,下一个时刻等于这一个时刻的和下一个时刻取最大,因为下一个时刻可能有哪个计划的终点落那了
第二种,另一个思路的dp,还在调,,,,,,
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
long long dp[maxn];
struct one{
int s;
int e;
int w;
};
one ori[maxn];
bool cmp(one a,one b){
return a.s>b.s;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>ori[i].s>>ori[i].e>>ori[i].w;
}
for(int i=1;i<=1000;i++){
dp[i+1]=max(dp[i],dp[i+1]);
for(int j=1;j<=n;j++){
if(i==ori[j].s){
dp[ori[j].e]=max(dp[i]+ori[j].w,dp[ori[j].e]);
}
}
}
cout<<dp[1000];
}
第十题 路径计数
题面:http://oj.daimayuan.top/problem/126
一开始想的直接暴力dfs,不过看了眼方案数要mod,dfs肯定超时了,然后根据dfs不行就试dp的思路,还真想到一个,dp[i][j]=dp[i-1][j]+dp[i][j-1],每一个点只可能从上面或左边过来,那直接把两边的方案数相加就得到当前点的方案数。
#include<bits/stdc++.h>
using namespace std;
long long mod=1e9+7;
int ori[110][110];
int n;
long long ans[110][110]={0};
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>ori[i][j];
}
}
ans[0][1]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(ori[i][j]==0)continue;
ans[i][j]=(ans[i][j-1]+ans[i-1][j])%mod;
}
}
cout<<ans[n][n];
}