Atcoder beginner contest 199
Atcoder ABC 199
A,B跳过
C:
题意:
给定一个字符串,有两种操作,第一种操作将两个字符调换,第二种操作将左右交换,输出最后的字符串。
解法:
通过题可以看出来我们需要用 \(O(n+q)\) 的时间复杂度的算法,第二种操作肯定不能直接用,因为 \(string\) 赋值也需要 \(O(n)\) 的时间复杂度。
因此,我们设置一个cnt用来记录左右交换的次数:
- \(n|2\), 为 \(l,r\);
- \(!n|2\),为 \(r,l\);
我们据此可以写出来交换的式子,分三种情况讨论即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,q,cnt;
string s,l,r,r2,l2;
int main()
{
cin>>n; cin>>s;
for(int i=0;i<n;i++) l+=s[i];
for(int i=n;i<2*n;i++) r+=s[i];
cin>>q;
while(q--){
int t,a,b;
scanf("%d%d%d",&t,&a,&b);a--,b--;
if(t==1){
char ch;
if(cnt%2==0){
if(a>=n&&b>=n) a=a-n,b=b-n,ch=r[a],r[a]=r[b],r[b]=ch;
else if(a<n&&b>=n) b=b-n,ch=l[a],l[a]=r[b],r[b]=ch;
else ch=l[a],l[a]=l[b],l[b]=ch;
}
else{
if(a>=n&&b>=n) a=a-n,b=b-n,ch=l[a],l[a]=l[b],l[b]=ch;
else if(a<n&&b>=n) b=b-n,ch=r[a],r[a]=l[b],l[b]=ch;
else ch=r[a],r[a]=r[b],r[b]=ch;
}
}
else cnt++;
}
if(cnt%2==0) cout<<l<<r<<endl;
else cout<<r<<l<<endl;
system("pause");
return 0;
}
D:
题意:
给你三种颜色和一个简单图,两个相邻的点(有路径)的颜色不同,问有多少种涂色方案。
解法:
点分两种:
- 独立点
- 有边点
对于独立点,我们选哪一种颜色就行,对于有边点,我们要进行深搜
可以这么想:我们枚举节点1的颜色,那么其连着的点就剩了两种颜色可以选,枚举颜色进行深搜即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int cnt[N],col[N],n,m;
#define ll long long
ll ans=0;
vector<ll> v[25];
ll dfs(ll x){
if(x>n) return 1;
if(v[x].size()==0) return 3*dfs(x+1);//空点,填什么颜色都可以
int res=0,color,i;
for(color=1;color<=3;color++){//选择填的颜色
for(i=0;i<v[x].size();i++)
if(col[v[x][i]]==color) break;
if(i!=v[x].size()) continue;//是否颜色相同
else{
col[x]=color;
res+=dfs(x+1);
col[x]=0;
}
}
return res;
}
int main()
{
cin>>n>>m;
for(int i=1,x,y;i<=m;i++){
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
for(int i=1;i<=3;i++){
col[1]=i;//对于第一个点的颜色,我们可以有3种颜色可以选
ans+=dfs(2);//从第二个点开始深搜
}
cout<<ans<<endl;
system("pause");
return 0;
}
E:
题意:
给定一个长为 \(n=\{1,2,3....n\}\) 的不可重序列,给定 \(m\) 个约束条件,即在第 \(1-x\) 的位上,最多有 \(z\) 个数小于等于 \(y\),求这种序列的个数。
做法:
看到数据范围一眼状压,正好选择数字可以看成一个01串。
对于dp,我们有这么一个状态转移方程:
\(dp[i|x]+=dp[i]\)
\(i|x\) 属于一个交集。
for(int j=0,x=1;j<n;j++,x<<=1)//枚举 另一集合的情况
if(!b[j]){//第几位没用,也就是不重复
bool flag=true;
for(int k=0;k<v[b.count()+1].size();k++){
int y=v[b.count()+1][k].first,z=v[b.count()+1][k].second;
int c=(j+1<=y)+f[y];//第y位原来用过的数字+(是否现在的数+1>y)=现在总数字
if(c>z){//数量多了
flag=false;break;
}
}
if(flag) dp[i|x]+=dp[i];//集合的并集+情况
}
这里面的 \(x\) 表示新的一位,这样计算就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define mk make_pair
#define pii pair<long long ,long long>
#define ll long long
#define int long long
int n,m;
const int N=20;
int dp[1<<N];
vector<pii> v[N];
signed main()
{
cin>>n>>m;
for(int i=1,x,y,z;i<=m;i++){
scanf("%lld%lld%lld",&x,&y,&z);
v[x].push_back(mk(y,z));
}
dp[0]=1;
for(int i=0;i<(1<<n);i++){//枚举所有用没用的情况
bitset<20> b(i);//用了哪些数字
ll f[20]={0};
for(int j=0;j<n;j++) f[j+1]=f[j]+b[j];//在第k+1位上用了f[j]+b[j]个数
for(int j=0,x=1;j<n;j++,x<<=1)//枚举 另一集合的情况
if(!b[j]){//第几位没用,也就是不重复
bool flag=true;
for(int k=0;k<v[b.count()+1].size();k++){
int y=v[b.count()+1][k].first,z=v[b.count()+1][k].second;
int c=(j+1<=y)+f[y];//第y位原来用过的数字+(是否现在的数+1>y)=现在总数字
if(c>z){//数量多了
flag=false;break;
}
}
if(flag) dp[i|x]+=dp[i];//集合的并集+情况
}
}
cout<<dp[(1<<n)-1]<<endl;
system("pause");
return 0;
}
F:
题意:
给一个 \(n\) 个顶点 \(m\) 条边的图,每一个顶点有一个权值,我们每次选择一条边,将边的两个顶点的权值编程两个顶点权值的平均值,求经过 \(q\) 次操作每个点权值的期望。
解法:
看成矩阵去计算....(不理解QWQ)
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,mod=1e9+7;
int val[N],deg[N];
#define ll long long
#define vll vector<ll>
#define vlll vector<vll>
vlll operator*(const vlll &x,const vlll &y){//矩阵乘法
vlll res(x.size(),vll(y[0].size()));
for(int i=0;i<x.size();i++)
for(int j=0;j<y[0].size();j++)
for(int k=0;k<y.size();k++)
res[i][j]=(res[i][j]+1ll*x[i][k]%mod*y[k][j]%mod)%mod;
return res;
}
vlll dp(vlll a,ll b){//矩阵快速幂
vlll res(a.size(),vll(a[0].size()));
for(int i=0;i<a.size();i++) res[i][i]=1;
while(b){
if(b&1) res=res*a;a=a*a;b>>=1;
}
return res;
}
ll qmi(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;a=a*a%mod;b>>=1;
}
return res;
}
int main()
{
int n,m,k;
cin>>n>>m>>k;
vlll a(n,vll(n));
vlll b(1,vll(n));
for(int i=0;i<n;i++) cin>>b[0][i];
for(int i=0,x,y;i<m;i++){
cin>>x>>y;x--,y--;
deg[x]++;deg[y]++;
a[x][y]=qmi(2*m,mod-2);
a[y][x]=qmi(2*m,mod-2);
}
for(int i=0;i<n;i++) a[i][i]=1ll*(2*m-deg[i])*qmi(2*m,mod-2)%mod;
vlll ans=b*dp(a,k);
for(int i=0;i<n;i++) cout<<ans[0][i]<<endl;
system("pause");
return 0;
}
结束!
不关注的有难了😠😠😠https://b23.tv/hoXKV9