K、Many Littles Make a Mickle(签到题)
先从最简单的签到题开始吧
#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
long long ans;
long long f(int n)
{
if(n<=0)return 0;
ans=n*n+f(n-1);
return ans;
}
int main()
{
int t;
cin>>t;
while(t--)
{
ans=0;
int n,m;
cin>>n>>m;
ans=f(n);
printf("%d\n",ans*m);
}
return 0;
}
L、It Rains Again
题意:给你两个坐标,看他能覆盖x有多长,这个比较标准的差分。只用考虑到他是否覆盖到这个区域,即差分数组的数组元素为正数的个数。
#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>
#include <math.h>
using namespace std;
int a[100010];
int main()
{
int t,_max=-1;
cin>>t;
while(t--)
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
a[x1]++;
a[x2]--;//差分
_max=max(_max,max(x1,x2));
}
int ans=0;
for(int i=0;i<=_max;i++)
{
a[i]+=a[i-1];
if(a[i])
ans++;
}
cout<<ans<<endl;
return 0;
}
B、Continued Fraction
题意:其实就是递归。但是我这一题的代码实现有点慢,希望自己在代码实现上面有一定突破。
#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int _count=1;
queue<int>q;
void f(int x,int y)
{
int m=y/x;
q.push(m);
_count++;
if(y%x==0){
cout<<_count-1<<" ";
return;}
f(y-m*x,x);
}
int main()
{
int t;
cin>>t;
while(t--)
{
_count=1;
int x,y;
cin>>x>>y;
int m=x/y;
q.push(m);
f(x-m*y,y);
while(1)
{
if(q.empty()==0)
{
int t=q.front();
printf("%d ",t);
q.pop();
}
else break;
}
cout<<endl;
}
return 0;
}
A、Mio visits ACGN Exhibition(dp)
题意:就是从给你n*m的矩阵的左上角(1,1)一直走到右下角(n,m),每一个方块呢,他都被赋予了值,要么0,要么1,然后问你有多少种路径,然后对走的路径也有一定的要求就是0的个数至少是p个,1的个数至少是q个。一开始对这道题的类型分析错了,以致看另外一道题去了,呜呜。
这里就涉及到了用滚动数组优化dp。
滚动数组是一种能够在动态规划中降低空间复杂度的方法,有时某些二维dp方程可以直接降阶到一维,在某些题目中甚至可以降低时间复杂度,是一种极为巧妙的思想。通过观察dp方程来判断需要使用哪些数据,可以抛弃哪些数据,一旦找到关系,就可以用新的数据不断覆盖旧的数据量来减少空间的使用。
完全背包的二维压成一维,这里借鉴了我们学校大佬的方法。大佬!
#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>
#include <math.h>
using namespace std;
#define mod 998244353
const int N=1005;
long long a[N][N];
long long f[N][N];
signed main()
{
// cout<<mod<<endl;
int n,m,p,q;
cin>>n>>m>>p>>q;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
cin>>a[i][j];
}
if(!a[1][1])
f[1][1]=1;
else f[1][0]=1;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
if(i!=1||j!=1)
{
if(a[i][j])
for(int k=i+j-1; k>=0; k--)
f[j][k]=(f[j-1][k]+f[j][k])%mod;//dp的转移方程
else
{
for(int k=i+j-1; k; k--)
f[j][k]=(f[j-1][k-1]+f[j][k-1])%mod;
f[j][0]=0;
}
}
}
int ans=0;
for(int i=p; i<=n+m-q-1; i++)
{
ans+=f[m][i];
ans%=mod;
}
cout<<ans<<endl;
}
D、Character Distance
这是一道都构造题。字典序。我练得比较少,队友负责,但是有一点弄错了,就是如果x只出现一次,ij不成对出现,那么就直接顺序输出,而不是"-1"
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long ll;
int a[N];
int b1[N],b2[N],b[N];
int pos,nb;
map<int,int> mp;
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
mp.clear();
ll n,d;int flag=0;
int pos1=-0x3f3f3f3f,pos2=-0x3f3f3f3f,nb1=0,nb2=0;
cin>>n>>d;
for(int i=1;i<=n;i++){
cin>>a[i];
mp[a[i]]++;
}
for(int i=1;i<=n;i++){
if(mp[a[i]]==1){
flag=1;break;//这就是我们没有考虑到的情况,如果x只出现一次
//那么按照顺序输出
}
}
sort(a+1,a+n+1);
if(d==1||flag==1){
for(int i=1;i<=n;i++)cout<<a[i]<<' ';
cout<<endl;
continue;
}
if(d>=n){
cout<<-1<<endl;
continue;
}
for(int i=n;i>0;){
//cout<<i<<endl; // 尾
ll num=mp[a[i]];
ll cha=(1ll*num-1ll)*(1ll*d-1ll)-(1ll*n-1ll*i);//所需长度和已给长度的比较
if(cha<=0){//后面够
if(pos1<(i-num+1)){
pos1=i-num+1;
nb1=a[i];
}
}
else{//后面不够
int head=i-num+1;
if(pos2<=(head-cha)&&(head>cha)){
pos2=head-cha;//放头位置
nb2=a[i];
}
}
i-=num;
}
if(pos1<1&&pos2<1){
cout<<"-1"<<endl;
continue;
}
if(pos1>0){
int num=mp[nb1],pos=pos1;int j=1,cnt=0;
for(int i=1;i<=n;i++){
if(a[j]==nb1){
j+=num;
}
if(i==pos&&cnt<num){
b1[i]=nb1;
pos+=d;cnt++;
}
else{
b1[i]=a[j++];
}
}
}
if(pos2>0){
int num=mp[nb2],pos=pos2;int j=1,cnt=0;
for(int i=1;i<=n;i++){
if(a[j]==nb2){
j+=num;
}
if(i==pos&&cnt<num){
b2[i]=nb2;
pos+=d;cnt++;
}
else{
b2[i]=a[j++];
}
}
}
if(pos1<1)
for(int i=1;i<=n;i++){
cout<<b2[i]<<' ';
}
else if(pos2<1)
for(int i=1;i<=n;i++){
cout<<b1[i]<<' ';
}
else{
int f=0;
for(int i=1;i<=n;i++){
if(b1[i]!=b2[i]){
if(b1[i]>b2[i])f=2;
else f=1;
break;
}
}
if(f==1){
for(int i=1;i<=n;i++){
cout<<b1[i]<<" ";
}
}else{
for(int i=1;i<=n;i++){
cout<<b2[i]<<" ";
}
}
}
cout<<endl;
}
return 0;
}
H、Hearthstone So Easy
这一道题就是如果他在第一手的时候没有杀掉对方,那么如果两个人一起回血,那么这个局面就进入了僵持的局面,那么这个时候杀不死后手,后手肯定会赢的,所以如果一开始没有杀死后手,那么后手必赢,这个时候还有一点很重要的就是,特判n==1.
#include<iostream>
#include<cstring>
#include<math.h>
#include<map>
#include<algorithm>
#define PI acos(-1)
using namespace std;
int main()
{
int T;
cin>>T;
while(T--)
{
int n,k;
cin>>n>>k;
if(n==1)cout<<"freesin"<<endl;
else if(1+k>=n)cout<<"pllj"<<endl;
else cout<<"freesin"<<endl;
}
return 0;
}
J、LRU
这个就是操作系统中LRU,然后呢,模拟一边,给你序列的长度n和需要命中的次数k。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int a[N];
struct node {
int idx, val;
bool operator<(const node& a) const { return idx < a.idx; }
};
inline bool check(int x, int n, int k){
set<node> se;//维护LRU表
unordered_map<int, int> mp;//维护出现的次数
int cnt = 0;
for (int i = 1; i <= n; ++i) {
if (mp.count(a[i])) {//如果已经出现,只需要替换就可以了
++cnt;
se.erase({mp[a[i]], a[i]});
se.insert({i, a[i]});
mp[a[i]] = i;
continue;
}
if (se.size() == x) {//如果满了且并没有出现过,则需要删除最先的数
node top = *se.begin();
se.erase(se.begin());
mp.erase(top.val);
}
mp[a[i]] = i;//直接加进去
se.emplace(node{i, a[i]});
}
return cnt >= k;
}
signed main(){
int n, k; cin >> n >> k;
for(int i = 1; i <= n; i++) cin >> a[i];
int l = 1, r = n + 1, ans = -1;
while(l <= r){//二分寻找答案
int mid = l + r >> 1;
if(check(mid, n, k)) r = mid - 1, ans = mid;
else l = mid + 1;
}
if(ans < 0) puts("cbddl");
else printf("%lld\n", ans);
return 0;
}