不知道在干什么,哈哈
A.Qualifiers Ranking Rules
题意:给定两场比赛的排名,进行去重,归并排序然后输出最后的rank
思路:实现输出即可
//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=0;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
int n,m;
std::vector<string> r1,r2,r3;
set<string>st;
string s;
void solve(){
cin>>n>>m;
st.clear();
for(int i=1;i<=n;i++){
cin>>s;
if(!st.count(s)){
st.insert(s);
r1.push_back(s);
}
}
st.clear();
for(int i=1;i<=m;i++){
cin>>s;
if(!st.count(s)){
st.insert(s);
r2.push_back(s);
}
}
st.clear();
for(int i=0;i<max(r1.size(),r2.size());i++){
if(i<r1.size()&&!st.count(r1[i])){
st.insert(r1[i]);
r3.push_back(r1[i]);
}
if(i<r2.size()&&!st.count(r2[i])){
st.insert(r2[i]);
r3.push_back(r2[i]);
}
}
for(auto v:r3){
cout<<v<<endl;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
}
L.KaChang!
题意:给定标程的运行时间和n个应该通过的程序的运行时间,问至少要开几倍的时间才能使所有程序通过(至少为2)
思路:排序,然后
m
a
x
(
(
a
[
i
]
+
t
−
1
)
/
t
,
2
)
max((a[i]+t-1)/t,2)
max((a[i]+t−1)/t,2)即可
//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=1e5+5;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
int n,t,a[N];
void solve(){
cin>>n>>t;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+1+n);
int ans=(a[n]+t-1)/t;
cout<<max(ans,2)<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
}
D.Transitivity
题意:给定一个不连通的图,如果一个子图连通那么其就是完全图,至少添加一条边,问最少添加几条边才能满足要求
思路:求出所有连通块,全部变成完全图,如果已经有了加边的操作,则已经满足要求。否则把两个拥有节点个数最少的联通块变成一个,然后再加边使其变成完全图。
//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=1e6+5;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
struct graph{
int cnte,hd[N];
struct edge{
int v,nt;
}e[N<<1];
void addedge(int v,int u){
e[++cnte].v=u;
e[cnte].nt=hd[v];
hd[v]=cnte;
}
};
graph g;
int n,m,vis[N];
int cnt=0;
pair<ll,ll>bk[N];
void dfs(int x){
vis[x]=1;
// cout<<cnt<<" "<<x<<endl;
bk[cnt].fi++;
for(int i=g.hd[x];i;i=g.e[i].nt){
int v=g.e[i].v;
bk[cnt].se++;
if(!vis[v]){
dfs(v);
}
}
}
void solve(){
cin>>n>>m;
for(int u,v,i=1;i<=m;i++){
cin>>u>>v;
g.addedge(u,v);
g.addedge(v,u);
}
for(int i=1;i<=n;i++){
if(!vis[i]){
cnt++;
bk[cnt].fi=bk[cnt].se=0;
dfs(i);
bk[cnt].se/=2;
}
}
sort(bk+1,bk+1+cnt);
ll add=0;
for(int i=1;i<=cnt;i++){
// cout<<bk[i].fi<<" "<<bk[i].se<<endl;
add+=bk[i].fi*(bk[i].fi-1)/2-bk[i].se;
}
if(add==0){
bk[0].fi=bk[1].fi+bk[2].fi;
bk[0].se=bk[1].se+bk[2].se;
add=bk[0].fi*(bk[0].fi-1)/2-bk[0].se;
}
cout<<add<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
}
J.Minimum Manhattan Distance
题意:给定两个不想交的园
c
1
c_1
c1和
c
2
c_2
c2。求在
c
2
c_2
c2里面或者边界上取一点,在
c
1
c_1
c1中均匀去点的最小期望。
思路:均匀!那应该使平均值了,所以只要计算C2中去某个点到达C1圆心的最小曼哈顿距离即可。
可以写出如下公式,
d
i
s
∗
s
i
n
α
+
d
i
s
∗
c
o
s
α
dis*sin\alpha+dis*cos\alpha
dis∗sinα+dis∗cosα,当角度为45时达到最大,减小的也最多,所以最小。
//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=0;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
struct point{
double x,y;
};
point a,b,c,d;
point getce(point a,point b){
point tmp;
tmp.x=(a.x+b.x)/2;
tmp.y=(a.y+b.y)/2;
return tmp;
}
double getdis(point a,point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void solve(){
cin>>a.x>>a.y>>b.x>>b.y;
cin>>c.x>>c.y>>d.x>>d.y;
point ce1=getce(a,b),ce2=getce(c,d);
//1 0.5 4.5 3.5
// cout<<ce1.x<<" "<<ce1.y<<endl;
// cout<<ce2.x<<" "<<ce2.y<<endl;
double disce=getdis(ce1,ce2),mh=fabs(ce1.x-ce2.x)+fabs(ce1.y-ce2.y);
double r1=getdis(a,b)/2,r2=getdis(c,d)/2;
double mhh=mh-sqrt(2)*r2;
// printf("%0.10lf\n",mh);
// printf("%0.10lf\n",r2);
printf("%0.10lf\n",mhh);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
I.Pa?sWorD
题意:给定长度为n的字符串由大写字母、小写字母、数字和问号组成。小写字母可以变成大写或者小写字母,问号可以变成任何字符(大写字母、小写字母、数字),问可以形成多少不同的字符串,大写字母、小写字母、数字各自至少出现一次且相邻字符不相同?
思路:求方案数,那只能用DP写了(不会容斥)。
设
f
i
,
v
,
j
,
k
,
l
f_{i,v,j,k,l}
fi,v,j,k,l为到达第i个位置上面的字符为v,大写字母是否出现(j),小写字母是否出现(k),数字是否出现(l)的方案数。
设
g
i
,
j
,
k
,
l
g_{i,j,k,l}
gi,j,k,l为到达第i个位置,大写字母是否出现(j),小写字母是否出现(k),数字是否出现(l)的方案数。
每次转移只要g减去特定的f即可。
可以状压,滚动数组优化。赛时写的很屎,哈哈。
//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=1e5+5;
const ll md=998244353;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
int n;
string s;
ll f[2][70][8],g[2][8];
void init(int now){
for(int j=1;j<=26+26+10;j++){
for(int k=0;k<8;k++){
f[now][j][k]=0;
}
}
for(int k=0;k<8;k++){
// f[now][j][k]=0;
g[now][k]=0;
}
}
int getk(int x,int v){
if(v>=1&&v<=26){
x|=1;
}else if(v>=27&&v<=26+26){
x|=2;
}else if(v>=26+26+1&&v<=26+26+10){
x|=4;
}
return x;
}
void solve(){
cin>>n;
cin>>s;
f[0][0][0]=1;
g[0][0]=1;
for(int i=1;i<=n;i++){
int l,r,add=1;
if(s[i-1]=='?'){
l=1,r=26+26+10,add=1;
}else if(s[i-1]>='a'&&s[i-1]<='z'){
l=1+s[i-1]-'a',r=27+s[i-1]-'a',add=26;
}else if(s[i-1]>='A'&&s[i-1]<='Z'){
r=l=27+s[i-1]-'A';
}else{
l=r=53+s[i-1]-'0';
}
int now=i%2,pre=now^1;
init(now);
// cout<<l<<" "<<r<<" "<<add<<endl;
for(;l<=r;l+=add){
for(int k=0;k<8;k++){
int kk=getk(k,l);
f[now][l][kk]+=(g[pre][k]-f[pre][l][k]+md)%md,f[now][l][kk]%=md;
g[now][kk]+=(g[pre][k]-f[pre][l][k]+md)%md,g[now][kk]%=md;
}
}
}
ll ans=0;
for(int i=1;i<=26+26+10;i++){
// cout<<f[n%2][i][7]<<endl;
ans+=f[n%2][i][7],ans%=md;
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
}
G.Spanning Tree
题意:给定操作序列和操作生成的数,操作如下定义:每一次操作分两步,第一步给定两个点,两个点在不同的联通块中。第二步,在a的联通块中随机取一个点v,在b的联通块中随机取一个点u,在v和u之间添加一条边。求形成给定的树的可能性。
思路:
首先,是树的结构。先不考虑合法不合法,经过操作形成的必然是一个树的结构。
钦定1为根进行dfs找到每个节点的父亲,顺便就可以处理出倍增数组,每次操作选择两个点,如果操作合法那么这两个点的连通块在树上是要相邻的,相邻就是通过一条边链接。所以可以找到每个点的最上面的父亲,设为ru,rv,如果ru的父亲与v属于同一联通块,或者rv的父亲和u属于同一联通块,那么便是合法的。进行带权并查集,计算概率。
思路很对,为什么没有写出来?因为操作序列与给定树输入反了,哈哈。让我们大声说
”谢谢Karashi 谢谢Karashi 谢谢Karashi“
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
using namespace std;
const int N=1e6+5;
const ll md=998244353;
const ll inf=1e18;
struct graph
{
int cnte,hd[N];
struct edge{
int v,nt;
}e[N<<1];
void addedge(int v,int u){
e[++cnte].v=u;
e[cnte].nt=hd[v];
hd[v]=cnte;
}
};
graph g;
int n,m;
int anc[N],rk[N];
int val[N],fa[N][21];
ll inv[N];
inline int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<3)+(x<<1)+(c^48); //等价于x*10+c-48,使用位运算加速
c=getchar();
}
return x*f;
}
inline void write(int x){
if(x<0)
putchar('-'),x=-x;
if(x>9)
write(x/10);
putchar(x%10+'0');
return;
}
inline int fd(int x){
if(anc[x]==x){
return x;
}
val[x]+=val[anc[x]];
return anc[x]=fd(anc[x]);
}
inline void uion(int u,int v){
int ru=fd(u),rv=fd(v);
if(ru!=rv){
// if(rk[ru]<rk[rv]){
// swap(ru,rv);
// }
anc[rv]=ru;//rv->ru
val[ru]+=val[rv];
// if(rk[ru]==rk[rv])rk[ru]++;
// val[rv]=0;
}
}
inline void dfs(int x,int p){
fa[x][0]=p;
// cout<<"dfs "<<x<<" "<<p<<endl;
for(int i=1;i<21;i++){
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for(int i=g.hd[x];i;i=g.e[i].nt){
int v=g.e[i].v;
if(v!=p){
dfs(v,x);
}
}
}
inline int fdh(int x){
int xx=x;
// cout<<"fdh"<<endl;
for(int i=20;i>=0;i--){
if(fa[x][i]!=0&&fd(fa[x][i])==fd(xx)){
// cout<<fa[x][i]<<endl;
x=fa[x][i];
}
}
// if(x==0)x=1;
// cout<<x<<" "<<xx<<endl;
return x;
}
inline ll ksm(ll a,ll b){
ll res=1;
while(b){
if(b&1)res=res*a%md;
b>>=1;
a=a*a%md;
}
return res;
}
inline ll getinv(ll a,ll b){
return ksm(a,b-2);
}
pair<int,int>op[N];
void solve(){
// cin>>n;
n=read();
for(int i=1;i<=n;i++){
anc[i]=i;
val[i]=1;
inv[i]=getinv(i,md);
}
for(int i=1;i<n;i++){
// cin>>op[i].fi>>op[i].se;
op[i].fi=read();
op[i].se=read();
}
for(int v,u,i=1;i<n;i++){
// cin>>v>>u;
v=read();
u=read();
g.addedge(u,v);
g.addedge(v,u);
}
dfs(1,0);
// cout<<"dfs end"<<endl;
ll ans=1;
// cout<<fa[3][0]<<endl;
for(int u,v,i=1;i<n;i++){
// cin>>u>>v;
u=op[i].fi;
v=op[i].se;
int fu=fdh(u),fv=fdh(v);
// cout<<fu<<" "<<fa[fu][0]<<" "<<fv<<" "<<fa[fv][0]<<endl;
if(fd(fa[fu][0])==fd(v)||fd(fa[fv][0])==fd(u)){
int ru=fd(u),rv=fd(v);
// cout<<val[ru]<<" "<<val[rv]<<endl;
ans=ans*inv[val[rv]]%md*inv[val[ru]]%md;
uion(u,v);
}else{
// cout<<"cant"<<endl;
ans=0;
}
}
// cout<<ans<<"\n";
write(ans);
putchar('\n');
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cout<<(1<<20)<<endl;
// cin>>t;
// cout<<getinv(240,md)<<endl;
while(t--){
solve();
}
}
没打好,下次好好打,至少要把能写的写出来。哈哈