【解题报告】CF DIV2 #ROUND 711 A~D
原创
©著作权归作者所有:来自51CTO博客作者鱼竿钓鱼干的原创作品,请联系作者获取转载授权,否则将追究法律责任
【解题报告】CF DIV2 #ROUND 711 A~D
比赛链接 虚拟赛,A了2题4000+名,还行
A.GCD Sum
思路
根据题意写就完事了,简单模拟
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
/*DATA & KEY
t 1 1e4
n 1 1e18
*/
int T;
LL gcd(LL a,LL b)
{
return b ? gcd(b, a % b) : a;
}
void solve(int T)
{
//NEW DATA CLEAN
//NOTE!!!
LL n;cin>>n;
for(LL i=n;;i++)
{
LL tmp=i;LL s=0;
while(tmp)
{
s+=tmp%10;
tmp/=10;
}
if(gcd(i,s)>1)
{
cout<<i<<endl;
break;
}
}
return ;
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
B.Box Fitting
思路
二分+贪心+优先队列
每组和不超过W,问最少分几组
有点类似书分组问题,不过书分组那个分必须是连续分的。这个是可以随便分组的。
check函数的贪心利用优先队列就实现即可。
先w[N]从大到小到排,先把数值大的排了,然后利用优先队列维护所有组最大剩余空间,如果可以放进去就更新压入堆,并弹出原来的堆顶,反之开一个新组。(这里的思想有点像这题)
但是写的时候WA了一波,原因是没有二分,只弄了check函数的贪心。
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
/*DATA & KEY
t 1 5e3
sum n 1 1e5
W 1 1e9
wi 1 1e6
*/
int T;
const int N=5e6+10;
LL w[N];
LL n,W;
bool check(LL mid)
{
priority_queue<LL,vector<LL>,greater<LL>>heap;
LL ans=0;
for(int i=n;i>=1;i--)
{
if(heap.empty())
{
heap.push(w[i]);
ans++;
}
else
{
if(W-heap.top()>=w[i])
{
int t=heap.top();
heap.push(t+w[i]);
heap.pop();
}
else
{
ans++;
heap.push(w[i]);
}
}
}
return ans<=mid;
}
void solve(int T)
{
//NEW DATA CLEAN
//NOTE!!!
cin>>n>>W;
for(int i=1;i<=n;i++)cin>>w[i];
sort(w+1,w+1+n);
LL l=1,r=n;
while(l<r)
{
LL mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<l<<endl;
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
C.Planar Reflections
思路
递归+记忆化,然后蜜汁写爆了样例RE
后来发现居然本地爆栈了!啊啊啊啊,交cf是可以直接AC的
后面本地加栈就没爆了
原本可以冲一波2000名的,淦
"C:\MinGW\bin\g++.exe" -Wall -std=c++11 -O2 -Wl,--stack=268435456
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long LL;
typedef pair<int,int> PII;
/*DATA & KEY
t 1 100
sum n 1 1000
sum k 1 1000
mod 1e9+7
*/
int T;
LL n,k;
const int mod=1e9+7,N=1e3+10;
LL f[N][N][2];
LL work(int k,int x,bool d)//k是衰变,x是第几层,d是方向
{
if(f[k][x][d]!=0)return f[k][x][d];
if(x==0||x==n+1)
{
return 1;
}
if(d==1)//原本向右
{
if(k>1)return f[k][x][d]=(work(k,x+1,1)+work(k-1,x-1,0))%mod;
else return f[k][x][d]=work(k,x+1,1)%mod;
}
else
{
if(k>1)return f[k][x][d]=(work(k,x-1,0)+work(k-1,x+1,1))%mod;
else return f[k][x][d]=work(k,x-1,0)%mod;
}
}
void solve(int T)
{
//NEW DATA CLEAN
memset(f,0,sizeof f);
//NOTE!!!
cin>>n>>k;
cout<<work(k,1,1)%mod<<endl;
}
int main()
{
scanf("%d",&T);
while(T--)solve(T);
return 0;
}
D.Bananas in a Microwave
思路
题目没看清然后BFS写烂了,不是按操作使用总和计数,而是第一次出现这个数在第几个操作。仔细分析样例的话就能看出来的,比如第一个样例的6按两种方法计算是不一样的。
inputCopy
3 20
1 300000 2
2 400000 2
1 1000000 3
outputCopy
-1 -1 1 -1 -1 1 -1 -1 -1 3 -1 2 3 -1 -1 3 -1 -1 -1 3
直接暴力和BFS都可以,大致思路想的差不多,但是又一次死在了时间复杂度的错误分析上。参看了这位大佬的博客恍然大悟,意识到自己是个憨憨。三重循环并不意味着时间复杂度就是这种
以操作步数为第一层循环,遍历0~m,如果已经出现过那就直接跳过,反之就扩展。时间复杂度为
另外写的时候不知道为什么ceilWA了,可以考虑手写上取整
代码
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define x first
#define y second
typedef long long LL;
typedef pair<int,int> PII;
/*DATA & KEY
n 1 200
m 2 1e5
ti 1 2
yi 1 m
type 2 xi/1e5 1 m
type 1 xi/1e5 (1,m]
*/
int T;
const int N=205,M=1e6+10,INF=0x3f3f3f3f;
struct Node{int op;LL x;int y;}a[N];
int n,m;
int num[M];
void solve()
{
//NEW DATA CLEAN
//NOTE!!!
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i].op>>a[i].x>>a[i].y;
for(int i=1;i<=m;i++)num[i]=INF;
for(int i=1;i<=n;i++)
{
for(int j=m;j>=0;j--)
{
if(num[j]==INF)continue;//如果没产生就不扩展
LL tmp=j;
for(int k=1;k<=a[i].y;k++)
{
if(a[i].op==1) tmp = tmp + (a[i].x + 100000 - 1) / 100000;//上取整
else tmp = (tmp *a[i].x + 100000 - 1) / 100000;
if(tmp>m)break;
if(num[tmp]!=INF)break;
num[tmp]=i;
}
}
}
for(int i=1;i<=m;i++)
if(num[i]==INF)cout<<-1<<" ";
else cout<<num[i]<<" ";
}
int main()
{
// scanf("%d",&T);
// while(T--)solve(T);
solve();
return 0;
}
看别的博客时候有人说这个问题像多重背包问题,确实挺像的,不过体积和物品价值挺难整的。不过这是一个好的联想。
n种物品----n种操作
每组物品s[i]个----每个操作可以进行y[i]次
物品总价值最大---到达某个操作使用物品数最少
物品选择价值增加----操作选择数字增加 抽象出物品价值
反思
A:
简单模拟,涉及对循环变量操作记得tmp变量
B:
区分数列分段问题是连续的,这个问题是可以不连续的,考虑把大的放进去。放的下就分一组放不下就新增一组
C:
递归分治思想,记得本地加栈啊啊啊
D:
时间复杂度分析:对于同一集合内采用类似hash或者bool数组方式双重循环的时候时间复杂度往往远小于O(NM)而是单层O(N)
如果是有限集合内类似BFS的扩展,可以考虑每次遍历整个集合,出现过的则在此基础上遍历,反之跳过这样扩展的时间复杂度约为O(N)
多重背包联想:可以把物品抽象为操作,物品种类抽象为操作种类,物品数量抽象为允许操作次数