场次链接
题目链接
A. Happy Birthday, Polycarp!
t个询问,每个询问给你一个n为上限,询问有多少个小于等于n并且所有位上数字一样的数。
数据范围: 1 ≤ t ≤ 1\leq t \leq 1≤t≤ 10 4 {\rm 10}^4 104, 1 ≤ n ≤ 1\leq n \leq 1≤n≤ 10 9 {\rm 10}^9 109
解:枚举所有位为1-9 暴力计数即可
复杂度: O ( 9 ∗ log 10 n ) O({9*\log_{10}n}) O(9∗log10n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void work()
{
ll n;
scanf("%lld",&n);
int ans=0;
for(int i=1;i<=9;i++){
ll k=i;
while(k<=n){
//printf("%lld\n",k);
ans++;
k=k*10+i;
}
}
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
//T=1;
while(T--){
work();
}
}
题目链接
B. Make Them Odd
给你n个数,然后每次可以选择一个偶数,使这n个数中所有等于这个数的数除以二,问最少要做几次才能使所有数都变成奇数。
数据范围: 1 ≤ t ≤ 1\leq t \leq 1≤t≤ 10 4 {\rm 10}^4 104, 1 ≤ n ≤ 1\leq n \leq 1≤n≤ 2 ∗ 10 5 2*{\rm 10}^5 2∗105, 1 ≤ s u m ( n ) ≤ 1\leq sum(n) \leq 1≤sum(n)≤ 2 ∗ 10 5 2*{\rm 10}^5 2∗105
解:如果两个偶数在不断除二后得到的是同一个奇数,则这两个数中小的那个数可以被大的那个数包含。所以将所有偶数不断除以二,将得到奇数的次数记录,取每一个奇数得到次数的最大值求和。
复杂度: O ( n ∗ log n ) O({n*\log n}) O(n∗logn)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void work()
{
map<int,int>m;
set<int>s;
int n;
scanf("%d",&n);
int maxx=0;
int ans=0;
for(int i=1;i<=n;i++){
int a;
scanf("%d",&a);
int cnt=0;
while(a%2==0){
cnt++;
a/=2;
}
if(cnt>=1){
m[a]=max(m[a],cnt);
s.insert(a);
}
}
set<int>::iterator it;
for(it=s.begin();it!=s.end();it++){
ans+=m[*it];
}
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
//T=1;
while(T--){
work();
}
}
题目链接
C. As Simple as One and Two
总共T个询问,每次给你一个字符串,你可以删掉其中的任意个数,要求最后字符串中不含有“one”和“two”,问最少要删几个。
数据范围: 1 ≤ t ≤ 1\leq t \leq 1≤t≤ 10 4 {\rm 10}^4 104, 1 ≤ 1\leq 1≤字符串长度 ≤ \leq ≤ 1.5 ∗ 10 5 1.5*{\rm 10}^5 1.5∗105, 1 ≤ 1\leq 1≤字符串总长 ≤ \leq ≤ 1.5 ∗ 10 6 1.5*{\rm 10}^6 1.5∗106
解:对于每一个我们找到的“one”和“two”,最简单的方法就是删掉’n’和’w’,但是有一个特殊情况需要考虑:“twone”,当这个情况时,最好的方法是删掉‘o’。模拟即可
复杂度: O ( n ) O(n) O(n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void work()
{
char a[2000005];
scanf("%s",a+1);
int l=strlen(a+1);
vector<int>v;
for(int i=1;i<=l-2;i++){
if(a[i]=='o'&&a[i+1]=='n'&&a[i+2]=='e'){
if(v.size()>0&&v[v.size()-1]==i){ //如果我刚删掉了‘o’则不用继续删
continue;
}else{
v.push_back(i+1);
}
}
if(a[i]=='t'&&a[i+1]=='w'&&a[i+2]=='o'){
if(i<l-2&&a[i+3]=='o') //如果后面是o那么选择删w,否则删o这样便于twone的判断
v.push_back(i+1);
else v.push_back(i+2);
}
}
printf("%d\n",v.size());
for(int i=0;i<v.size();i++){
printf("%d ",v[i]);
}
printf("\n");
}
int main()
{
int T;
scanf("%d",&T);
//T=1;
while(T--){
work();
}
}
题目链接
D. Let’s Play the Words?
t个询问,每个询问给n个字符串,每个字符串只有0和1两种数,让你对这些字符串进行串联,要求为前一个字符串的最后一个数和后一个字符串的第一个数相同。你可以反转其中的一些字符串,例如’011’反转为’110’。但是要求最后答案中所有字符串均不相同。要求反转次数小于等于n,如果无法满足,输出-1。如果可以满足,输出反转次数和反转的哪些字符串。
数据范围: 1 ≤ t ≤ 1\leq t \leq 1≤t≤ 10 4 {\rm 10}^4 104, 1 ≤ n ≤ 1\leq n \leq 1≤n≤ 2 ∗ 10 5 2*{\rm 10}^5 2∗105, 1 ≤ 1\leq 1≤字符串长度 ≤ \leq ≤ 4 ∗ 10 6 4*{\rm 10}^6 4∗106, 1 ≤ s u m ( n ) ≤ 1\leq sum(n) \leq 1≤sum(n)≤ 2 ∗ 10 5 2*{\rm 10}^5 2∗105, 1 ≤ 1\leq 1≤字符串总长 ≤ \leq ≤ 4 ∗ 10 6 4*{\rm 10}^6 4∗106
解:将字符串按照首位和末位分为4类。字符串满足01-11-11-……-11-10-01,10-00-00-00-……-00-01这样的循环。如果要满足题目要求,那么01和10的数量差应该小于等于1,那么将多的进行反转(注意反转后是否重复),使得01和10数量差小于等于1。
特判:如果10和01均为0,那么需要11和00其中一个为0才能满足,否则不满足
复杂度: O ( n ) O(n) O(n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int vis[200005];
map<string,int>m;
vector<int>v[4];
void work()
{
int n;
cin>>n;
m.clear();
v[0].clear();
v[1].clear();
v[2].clear();
v[3].clear();
for(int i=1;i<=n;i++){
string a;
cin>>a;
if(a[0]=='0'&&a[a.length()-1]=='0')v[0].push_back(i);
if(a[0]=='0'&&a[a.length()-1]=='1')v[1].push_back(i);
if(a[0]=='1'&&a[a.length()-1]=='0')v[2].push_back(i);
if(a[0]=='1'&&a[a.length()-1]=='1')v[3].push_back(i);
m[a]=i;
reverse(a.begin(),a.end());
if(m[a]){
vis[m[a]]=1;
vis[i]=1;
}else{
vis[i]=0;
}
}
if(v[1].size()==v[2].size()&&v[1].size()==0){
if(v[0].size()==0||v[3].size()==0){
cout<<"0"<<endl;
}else{
cout<<"-1"<<endl;
}
}else{
int k;
int cnt;
if(v[1].size()>v[2].size()){
k=1;
cnt=v[1].size()-v[2].size();
}else{
k=2;
cnt=v[2].size()-v[1].size();
}
cnt/=2;
vector<int>ans;
for(int i=0;i<v[k].size();i++){
if(cnt==0){
break;
}
if(vis[v[k][i]]==0){
ans.push_back(v[k][i]);
cnt--;
}
}
if(cnt!=0){
cout<<"-1"<<endl;
}else{
cout<<ans.size()<<endl;
for(int i=0;i<ans.size();i++){
cout<<ans[i]<<" ";
}
cout<<endl;
}
}
}
int main()
{
std::ios::sync_with_stdio(false);
int T;
cin>>T;
//T=1;
while(T--){
work();
}
}
题目链接
E. Two Fairs
n个点,m条边,给a,b两点,问有多少组(x,y),x,y之间所有的路径都经过a和b,经过顺序任意。
数据范围: 1 ≤ t ≤ 4 ∗ 10 4 1\leq t \leq 4*{\rm 10}^4 1≤t≤4∗104, 1 ≤ n ≤ 2 ∗ 10 5 1\leq n \leq 2*{\rm 10}^5 1≤n≤2∗105, n − 1 ≤ m ≤ 5 ∗ 10 5 n-1\leq m \leq 5*{\rm 10}^5 n−1≤m≤5∗105, 1 ≤ s u m ( n ) ≤ 2 ∗ 10 5 1\leq sum(n) \leq 2*{\rm 10}^5 1≤sum(n)≤2∗105, s u m ( m ) ≤ 5 ∗ 10 5 sum(m) \leq 5*{\rm 10}^5 sum(m)≤5∗105
解:给a点赋值1,b点赋值2,以a,b为原点跑bfs(注意vis[a]和vis[b]先设为3),bfs完之后,vis值为3的即是可以不同时经过a,b2点就到达的,答案即vis为1的数量*vis为2的数量。
复杂度: O ( n ) O(n) O(n)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node
{
int v;
int id;
};
int vis[200005];
vector<int>v[500005];
void work()
{
int n,m,a,b;
scanf("%d%d%d%d",&n,&m,&a,&b);
for(int i=1;i<=n;i++){
vis[i]=0;
v[i].clear();
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
node k;
k.v=1;
k.id=a;
vis[a]=3;
queue<node>q;
q.push(k);
k.v=2;
k.id=b;
vis[b]=3;
q.push(k);
while(!q.empty()){
k=q.front();
q.pop();
for(int i=0;i<v[k.id].size();i++){
//printf("%d\n",vis[v[k.id][i]]);
if(vis[v[k.id][i]]!=k.v&&vis[v[k.id][i]]!=3){
vis[v[k.id][i]]+=k.v;
node nxt;
nxt.id=v[k.id][i];
nxt.v=k.v;
q.push(nxt);
}
}
}
ll x=0,y=0;
for(int i=1;i<=n;i++){
//printf("%d ",vis[i]);
if(vis[i]==1){
x++;
}
if(vis[i]==2){
y++;
}
}
//printf("\n");
printf("%lld\n",x*y);
}
int main()
{
int T;
scanf("%d",&T);
//T=1;
while(T--){
work();
}
}
F. Beautiful Rectangle
给n个数,组成一个矩形,要求每行每列没有数字重复,问能组成的面积最大的矩形。
数据范围: 1 ≤ n ≤ 4 ∗ 10 5 1\leq n \leq 4*{\rm 10}^5 1≤n≤4∗105, 1 ≤ a [ i ] ≤ 10 9 1\leq a[i] \leq {\rm 10}^9 1≤a[i]≤109
解:首先判断矩阵的大小,枚举列数(即每种数最多几个),判断能组成几行,然后取面积最大值。然后将所有数枚举暴力斜着排列到矩形中。
复杂度: O ( n ∗ log n ) O(n*\log n) O(n∗logn)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node
{
int id;
int sum;
}num[400005];
map<int,int>m;
node ans[400005];
int cnt[400005];
vector<int>v[400005];
int s[400005];
bool cmp(node x,node y)
{
return x.sum>y.sum;
}
void work()
{
int n;
scanf("%d",&n);
int tot=0;
for(int i=1;i<=n;i++){
int a;
scanf("%d",&a);
if(m[a]){
num[m[a]].sum++;
}else{
num[++tot].id=a;
num[tot].sum=1;
m[a]=tot;
}
}
sort(num+1,num+tot+1,cmp);
for(int i=1;i<=tot;i++){
s[i]=num[i].sum;
s[i]+=s[i-1];
}
int tmp=1,ans=0,ansp,ansi;
for(int i=tot;i>=1;i--){
while(num[tmp].sum>i)tmp++;
int tmpp;
tmpp=tmp*i+n-i-s[tmp-1];
if(tmpp/i<i)continue;
if(tmpp/i*i>ans){
ans=(tmpp/i)*i;
ansp=tmpp;
ansi=i;
}
}
int p,q;
p=ansi;
q=ans/ansi;
printf("%d\n",q*p);
printf("%d %d\n",q,p);
for(int i=0;i<q;i++){
v[i].resize(p);
}
int x=0,y=0;
int pi=1,ti=0,xypi=0,xyti=0;
for(int i=0;i<p*q;i++){
//printf("??%d %d %d\n",y,x,num[pi].id);
v[x][y]=num[pi].id;
y++,x=(x+1)%q;
xyti++;
if(xyti==p){
xyti=y=0;x=++xypi;
}
ti++;
if(ti==min(p,num[pi].sum)){
pi++;
ti=0;
}
}
for(int i=0;i<q;i++){
for(int j=0;j<p;j++){
printf("%d ",v[i][j]);
}
printf("\n");
}
}
int main()
{
int T;
//scanf("%d",&T);
T=1;
while(T--){
work();
}
}