开学过半 (cf补题和算法训练)
题意:
给你一个n和一个k,让你找到1到k里的一个数x,让n*x得出的结果尾巴的0要尽可能地多
如果无论这么搞都没有,那么就输出n*k即可
题解:
我们先想一下 0是怎么来的
是不是由2*5得来,所以我们想要更多地0,我们就需要在n里面找多余地2和5
里面地2和5会相互成0,所以我们找出多余地,然后用在x里面乘就行了,就是用x里面地2 或者 5去帮n补0
这个就是分离因子地思想
然后统计一下10
最后m/x*x就是在k里面找地最大数咯
#include <bits/stdc++.h> #pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long //#define endl '\n'; using namespace std; const int N=2e5+7,M=1e1; const int INF = 0x3f3f3f3f; const int mod=100003; typedef pair<int,int> PII; int a[N]; int n,m; void solve() { cin>>n>>m; int t=n; int ans2=0,ans5=0; while (t%2==0) { ans2++; t/=2; } t=n; while (t%5==0) { ans5++; t/=5; } int x=1; while (ans2>ans5 && x*5<=m) { x*=5; ans2--; } while (ans2<ans5 && x*2<=m) { x*=2; ans5--; } while (x*10<=m) { x*=10; } cout<<m / x * x * n<<'\n'; } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; cin>>T; while(T--){ solve(); } return 0; }
题意:给你一个进制p和一串数字,然后你可以断加一在尾数,要是满则进一
现在要求你实现,要出现0到p-1的数字,问你需要加几次
题解:一看就只有两种情况
首先我们用map统计出现的数字
一:就是尾数之前的数字都存在我们只需要尾数不断加一向前跑,不需要进位,就可以出现所以数,答案就是最后一个出现的数减尾数
二:就是需要进位,那没进位时我们需要模拟过程,把进位过程中出现的数字都标记
然后在由0跑的尾数即可
(注意如果前面没有数字的时候,如果第一个数字满足了p,我们需要多搞出一位这一位等于1)标记1
#include <bits/stdc++.h> //#pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long //#define endl '\n'; using namespace std; const int N=300010,M=1e1; const int INF = 0x3f3f3f3f; const int mod=1e9+7; typedef pair<int,int> PII; int dx[4]={1,-1,0,0}; int dy[4]={0,0,1,-1}; int a[N]; void solve() { int n,p; cin>>n>>p; map<int,int> mp; a[0]=0; for(int i=1;i<=n;i++) { cin>>a[i]; mp[a[i]]=1; } int f=0; for(int i=0;i<a[n];i++) { if(!mp[i]) { f=1; break; } } if(f!=1) { int ans=p-1; while (mp[ans]) ans--; cout<<max(0ll,ans-a[n])<<endl; } else { int x=0; x+=p-a[n]; mp[0]=1; int ans=0; int y=a[n]-1; a[n]=0; for(int i=n-1;i>=1;i--) { a[i]++; ans++; if(a[i]==p) a[i]=0; mp[a[i]]=1; if(a[i]) break; } if(ans==n-1 && a[1]==0) mp[1]=1; while (mp[y]) { y--; } x+=max(0ll,y); cout<<x<<endl; } } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; cin>>T; while(T--){ solve(); } return 0; }
题意:给你一个n*m的矩阵,里面只有0和1 ,然后你需要从1,1点到n,m 点,你走的路径必须全部是回文串,就是第一个和最后一个位置的数字相等
倒数第二个和第二格相等,以此类推,要让全部可行路径都的是回文的,你可以改变某个位置的0或者1
现在让你通过最少改变的次数实现全部路径都是回文的
题解:我们想一下,这里的意是回文就是(1,1)和(n,m)对应 (1,2)和(n-1,m) 或者(n,m-1) 对应,所以我们发现前面的点加后面的对应点无论如何的等于
x1+y1+x2+y2=n+m+2,所以我们可以推出目标点x2+y2=n+m+2-x1-x1 这样我们就可以找出对应点了,让这些对应点都等于对应点集合里最大数即可
所以我们用一个数组存1和0的个数,然后把一和0全加上在删除最大个数就是答案
这里注意,如果回文是个基数串,中间的就不需要改变,所以就不要遍历到(n+m+2)/2(这个的意思是集合里面就有这么多个集合)
#include <bits/stdc++.h> //#pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long #define endl '\n'; using namespace std; const int N=1000,M=1e1; const int INF = 0x3f3f3f3f; const int mod=1e9+7; typedef pair<int,int> PII; int dx[4]={1,-1,0,0}; int dy[4]={0,0,1,-1}; int a[N][N]; int num[N][2]; void solve() { int n,m; cin>>n>>m; ::memset(num,0,sizeof (num)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { cin>>a[i][j]; if(a[i][j]==0) { num[i+j][0]++; } else { num[i+j][1]++; } } } int ans=0; if((n+m)%2==1) { for(int i=2;i<=(n+m+2)/2;i++) { ans+=num[i][0]+num[i][1]+num[n+m+2-i][0]+num[n+m+2-i][1]-max(num[i][0]+num[n+m+2-i][0],num[i][1]+num[n+m+2-i][1]); } } else { for(int i=2;i<(n+m+2)/2;i++) { ans+=num[i][0]+num[i][1]+num[n+m+2-i][0]+num[n+m+2-i][1]-max(num[i][0]+num[n+m+2-i][0],num[i][1]+num[n+m+2-i][1]); } } cout<<ans<<endl; } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; cin>>T; while(T--){ solve(); } return 0; }