Codeforces Round #606 Div. 2 Dec/14/2019 19:05UTC+8
比赛链接 https://codeforces.com/contest/1277
比赛记录 https://blog.csdn.net/cheng__yu_/article/details/105395197
D. Let’s Play the Words?(分类)
题意:给定 n 个不同的01串。每个串进行接龙01接10,10接01。可以对一些串进行翻转进行连接,但连接后每个串依然是不同的。问最少需要翻转多少个串
思路:一共有4种串。00和11串需要01和10串连接。然后就是01串和10串,将多出来的部分,翻转其中的二分之一
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10,inf=2e9;
int t,n;
string s;
map<string,int> pos;
vector<int> ans;
set<string> st[4];
void solve(set<string> &a,set<string> &b)
{
int d=a.size()-b.size();
for(auto i : a)
{
if(ans.size()==d/2) break;
string t=i;
reverse(t.begin(),t.end());
if(b.count(t)) continue;
ans.push_back(pos[i]);
}
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
for(int i=0;i<=3;++i) st[i].clear();
pos.clear();
ans.clear();
for(int i=1;i<=n;++i)
{
cin>>s;
pos[s]=i;
int m=s.size();
int a=s[0]-'0',b=s[m-1]-'0';
int p=a*2+b;
st[p].insert(s);
}
if(!st[0].empty()&&!st[3].empty()&&st[1].empty()&&st[2].empty())
{
puts("-1");
continue;
}
if(st[1].size()>=st[2].size()) solve(st[1],st[2]);
else solve(st[2],st[1]);
cout<<ans.size()<<"\n";
for(auto i : ans)
cout<<i<<" ";
cout<<"\n";
}
return 0;
}
E. Two Fairs(思维 + 图)
链接:https://codeforces.com/contest/1277/problem/E
题意:给定一张无向联通图,给定两个点 a、b。问有多点对(x,y),从 x 到 y 必须通过 a 和 b。
思路:
- 画个图可以发现,同时经过 a、b 的路径,就是那些只能到达 a 的点数 乘上 只能到达 b 的点数
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10,inf=2e9;
int t,n,m,a,b;
int visit[maxn];
vector<int> e[maxn];
void dfs(int u,int b)
{
if(u==b)
return;
for(auto v : e[u])
{
if(visit[v]) continue;
visit[v]=1;
dfs(v,b);
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&n,&m,&a,&b);
for(int i=1;i<=n;++i)
e[i].clear(),visit[i]=0;
for(int i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
ll cnt1=0,cnt2=0;
dfs(a,b);
for(int i=1;i<=n;++i)
if(!visit[i])
cnt1++;
for(int i=1;i<=n;++i) visit[i]=0;
dfs(b,a);
for(int i=1;i<=n;++i)
if(!visit[i])
cnt2++;
printf("%lld\n",cnt1*cnt2);
}
return 0;
}
F. Beautiful Rectangle(构造矩阵)
链接:https://codeforces.com/contest/1277/problem/F
题意:给定 n 个数让你组成一个最大矩阵,要求矩阵每行每列没有相同的数
思路:首先可以知道相同的数最多可以取,min(R,C) 个 。假设 R<=C,相同的数可以取 R 个,然后枚举最大的R,得到解之后,构造矩阵即可
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=4e5+10,inf=2e9;
int n;
int a[maxn],cnt[maxn];
struct Node
{
int v,t;
bool operator<(const Node &b) const
{
return t>b.t;
}
}b[maxn];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+1+n);
memset(b,0,sizeof(b));
int m=0;
for(int i=1;i<=n;++i)
if(a[i]==a[i-1]) b[m].t++;
else b[++m].v=a[i],b[m].t=1;
sort(b+1,b+1+m);
for(int i=1;i<=m;++i)
cnt[b[i].t]++;
int row,mx=0,sum=0,tot=m;
for(int i=1;i*i<=n;++i)
{
int t=sum+tot*i;
sum+=cnt[i]*i;
tot-=cnt[i];
if(t/i*i>mx&&i<=t/i)
{
row=i;
mx=t/i*i;
}
}
int col=mx/row;
vector<vector<int> > ans(row,vector<int>(col));
int k=0;
for(int i=1;i<=m;++i)
{
int t=min(b[i].t,row);
while(t--)
{
if(k==row*col)
break;
int r=k%row,c=(k/row+k%row)%col;
ans[r][c]=b[i].v;
k++;
}
}
printf("%d\n%d %d\n",mx,row,col);
for(int i=0;i<row;++i)
for(int j=0;j<col;++j)
printf("%d%c",ans[i][j],j==col-1?'\n':' ');
return 0;
}