HDU多校五

总结:
1001题找到了相应的结论,然后顺利过了,其它题做的不是很顺利。

1003

题意

给出n张纸,从左右向右对折k次,给出标注的数字,然后按照题目图中所给出的形式还原原来纸上的数字序列。

思路

模拟还原对折的过程。给出标注的数字,从头开始,每两个数字为一对,是同一张纸的上下两面的数字。还原一次对折,就是将序列其中一半数字对上下颠倒后,排到还原后在同一张纸平面上的对应数字序列中。还原完成后,有n个序列,按照数字对顺序依次输出,先输出所有数字对其中一个,再输出所有数字对另外一个。

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false),cin.tie(0);
#define ll long long
#define inf 0x3f3f3f3f
const int N=1e5+5;
//set<string>b;
//set<string>::iterator it;
const int M=5e3+5;
deque<pair<int,int>>a[N];
int b[M];
void init()
{
	int i;
	b[0]=1;
	for(i=1;i<=10;i++) b[i]=b[i-1]*2;
}
int main()
{
    IO;
    init();
    int T,n,k,i,j,len,x,y,temp;
    cin>>T;
    while(T--)
    {
		cin>>n>>k;
    	for(i=n*b[k];i>=1;i--)
    	{
    		cin>>x>>y;
    		a[i].push_front({x,y});
		}
		len=n*b[k];
		for(i=1;i<=k;i++)
		{
			for(j=len;j>=len/2+1;j--)
			{
				temp=len-j+1;
				while(!a[j].empty())
				{
					pair<int,int>now=a[j].front();
					a[j].pop_front();
					now={now.second,now.first};
					a[temp].push_front(now);
				}
			}
			len/=2;
		}
		for(i=n;i>=1;i--)
		{
			vector<pair<int,int>>v;
			while(!a[i].empty())
			{
				v.push_back(a[i].front());
				a[i].pop_front();
			}
			for(j=0;j<v.size();j++)
			{
				cout<<v[j].first<<" ";
			}
			for(j=0;j<v.size();j++)
			{
				cout<<v[j].second;
				if(j==v.size()-1&&i==1) continue;
				cout<<" ";
			}
		}
		cout<<endl;
	}
    return 0; 
}

1005

题意

给你一张无向联通图,图中的结点属于三种类型中的一种,这三种类型分别为M,L,R。从L/R结点到R/L结点要多花费x的时间,求从s点到t点最少要花费多少时间。

思路

把每个点拆成两个点,左点拆成两个左点,右点拆成两个右点,中间点拆成一左一右两个点,然后跑dijsktra

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+10;
const ll inf=1e18;
int n,m,s,t,cost;
string ss;
struct node {
    int u;
    int v;
    int w;
    int next;
}edge[maxn*8];
int head[maxn*3];
int tol=0;
void addedge (int u,int v,int w) {
    edge[tol].u=u;
    edge[tol].v=v;
    edge[tol].w=w;
    edge[tol].next=head[u];
    head[u]=tol++;
    
    edge[tol].u=v;
    edge[tol].v=u;
    edge[tol].w=w;
    edge[tol].next=head[v];
    head[v]=tol++;
}
ll d[maxn];
int visit[maxn];
char wjm[maxn];
struct qnode {
    int v;
    ll w;
    bool operator < (const qnode &r) const {
        return w>r.w;
    }
};
void dij (int s) {
    memset(visit,0,sizeof(visit));
    for (int i=1;i<=2*n;i++) d[i]=inf;
    priority_queue<qnode> q;
    d[s]=0;
    q.push({s,0});
    qnode tmp;
    while (!q.empty()) {
        tmp=q.top();
        q.pop();
        int u=tmp.v;
        if (visit[u]) continue;
        visit[u]=1;
        for (int i=head[u];i!=-1;i=edge[i].next) {
            int v=edge[i].v;
            int tt;
            if (wjm[u]==wjm[v])
                tt=0;
            else
                tt=1;
            if (!visit[v]&&d[v]>d[u]+edge[i].w+tt*cost) {
                d[v]=d[u]+edge[i].w+tt*cost;
                //if (!visit[v]) {
                    q.push({v,d[v]});
                    //visit[v]=1;
                //}
            }
        }
    } 
}
int main () {
    int T;
    scanf("%d",&T);
    while (T--) {
        scanf("%d%d%d%d%d",&n,&m,&s,&t,&cost);
        for (int i=1;i<=n*2;i++) head[i]=-1;
        cin>>ss;

        for (int i=1;i<=n;i++) {
            if (ss[i-1]=='L') {
                wjm[i]='L';
                wjm[i+n]='L';
            }
            else if (ss[i-1]=='R') {
                wjm[i]='R';
                wjm[i+n]='R';
            }
            else {
                wjm[i]='L';
                wjm[i+n]='R';
            }
        } 
        tol=0;
        for (int i=0;i<m;i++) {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(u+n,v,w);
            addedge(u+n,v+n,w);
            addedge(u,v+n,w);
        }
        ll ans=1e18;
        dij(s);
        ans=min(ans,d[t]);
        ans=min(ans,d[t+n]);
        dij(s+n);
        ans=min(ans,d[t]);
        ans=min(ans,d[t+n]); 
        printf("%lld\n",ans);
    }
    return 0;
}



1001

题意

• 题意:从[1,n]随机生成直角四面体的三边,求顶点到底面高h的 1/(n^2)。

思路

先手算得到1/h^2=1/a^2+1/b^2+1/c^2。然后预处理1-n的所有倒数的平方和,分数取模要用到逆元。

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false),cin.tie(0);
#define ll long long
#define inf 0x3f3f3f3f
const int N=6e6+5;
const int M=6e6;
const int mod=998244353;

ll inv[N];
ll b[N];
void init()
{
    inv[1] = 1;
    for (int i = 2; i <= M; ++i) inv[i] = (long long)(mod - mod / i) * inv[mod % i] % mod;
}
void getb()
{
    b[1]=1;
    for(int i=2;i<=M;++i)
    b[i]=(b[i-1]+inv[i]*inv[i]%mod)%mod;
}
int main()
{
    IO;
    init();
    getb();
    int T;
    ll n,ans;
    cin>>T;
    while(T--)
    {
        cin>>n;
        ans=3*b[n]*inv[n]%mod;
        cout<<ans<<endl;
    }
    return 0; 
}

1009

题意

对一张纸,随机产生 n 个操作,操作有四种类型:从左往右折,从右往左折,从上往下折,从下往上折,对最后的纸横竖各切一刀,求纸的期望数量。

思路

拿个纸折一下会发现,横向折会影响竖刀口的数量,竖着折会影响横刀口的数量,若横刀口为 x,竖刀口为 y,纸显然为 (2x+1)∗(2y+1)(2x+1)∗(2y+1) 张,再观察一下可以发现折纸的顺序,不影响对刀口数量的影响。
所有操作的可能数为 4n4n,考虑枚举 n 个操作有几个横折操作,设有 xx 个,这种方案的概率为:C(n,x)∗2x∗2n−x4nC(n,x)∗2x∗2n−x4n,贡献为 (2x+1)∗(2n−x+1)(2x+1)∗(2n−x+1),拆开得到 2n+1+2x+2n−x2n+1+2x+2n−x,后面两项求和就是 2∗3n2∗3n,因此答案就是 2n+1+2∗3n2n

代码

#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int maxn = 5e5 + 10;
typedef long long ll;
int t;
ll fpow(ll a,ll b) {
    ll r = 1;
    while (b) {
        if (b & 1) r = r * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return r;
}
int main() {
    scanf("%d",&t);
    while (t--) {
        ll n;
        scanf("%lld",&n);
        ll t1 = 2 * fpow(3,n) % mod, t2 = fpow(2,n);
        ll res = t1 * fpow(t2,mod - 2) % mod;
        printf("%lld\n",(res + t2 + 1) % mod);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值