zoukankan      html  css  js  c++  java
  • test20190331

    贪吃蛇(snaker.cpp/.in.out 1S 512M)

    【题目描述】

    C 最近爱上了玩贪吃蛇,想要自己制作一款贪吃蛇游戏,但是她太弱了,只会写一个一维的程序。
    游戏界面可以看做一条长为 n 的直线,方便起见我们给它标号从1~n。每个 i ~ i + 1(i <= n - 1)的一段中有一条长度为 A[i] 小虫,吃掉它 C 的贪吃蛇的身长就会变长A[i]。

    C 会进行多次游戏,每次从l到 r这一段中任选一个点开始游戏

    【输出数据】

    对于每次询问回答一行,输出一个既约分数
    若答案为整数 a,输出 a/1

    【样例输入】

    4 5
    C 1 4 2
    C 1 2 -1
    Q 1 2
    Q 2 4
    Q 1 4

    【样例输出】

    1/1
    8/3
    17/6

    【数据范围】

    对于 30%的数据,1 <= n, m <= 1000;
    对于 50%的数据,1 <= n, m <= 10000;
    对于 100%的数据,1 <= n, m <= 100000;
    所有 C 与 Q 中保证 1 <= l < r <= n
    任何情况下小虫的长度总为不超过 10000 的非负整数

    优美的字符串(string.cpp/.in.out 1S 512M)

    【题目描述】

    定义这样的字符串是优美的:

    1. 字符串包含最多 n 个不同的字符,字符标号 1 ~ n 。
    2. 对于标号为 i 的字符,如果 2 * i > n,那么这个字符可以作为优美的字符串的结尾,且这个字符后面可以是任何字符;如果 2 * i <= n,那么这个字符不能做优美的字符串的末尾,并且他后面接的字符的编号必须要大于等于 2 * i。

    求长度为 m 的优美的字符串有多少个,输出答案对 1000000007 取模的结果

    【输入数据】

    一行两个整数 n, m 。

    【输出数据】

    一行一个整数表示答案。

    【输入样例】

    6 3

    【输出样例】

    73

    【数据范围】

    对于 20% 的数据,n <= 6, m <= 10 。
    对于 60% 的数据,n <= 10000, m <= 100000 。
    对于 100% 的数据,n <= 1000000, m <= 1000000000000000000 。
    数据有梯度。

    C 题(c.cpp/.in.out 1S 512M)

    【题目描述】

    森林里共有 n 个结点,结点从 1 到 n 编号。森林里共有 m 条有向边,一些结点之间通过有向边连接。通过有向边可以从一个结点走到另一个结点,但是通过一条边需要花费其所对应的时间。

    有一天,一名农夫闯入了森林。他观察发现,每天都会有一只兔子从 1 号结点跑到 n号结点。兔子都很聪明,它总会选择一条从 1 到 n 花费总时间最少的路径,但是兔子每天可能会选择不同的路径。农夫仔细研究之后发现无论兔子选择哪条最短路径,都必须经过一些特定的结点。也就是说,任何一条从 1 到 n 的最短路都要经过这些结点。于是他只要选择一个这样的结点,在那里“守株待兔”便可以抓到兔子了。现在他想知道这样的结点一共有多少个。

    【输入数据】

    第一行两个数 n,m 表示木桩数和边数。
    接下来有 m 行,每行 3 个数 u v w,表示从 u 号木桩到 v 号木桩有一条耗时为 w 的有向边。
    输入保证没有自环和重边。

    【输出数据】

    如果不能从 1 号木桩到 n 号木桩输出-1,否则输出特定木桩个数。

    【输入样例】

    5 5
    1 2 2
    1 3 5
    2 4 1
    3 4 4
    4 5 10

    【输出样例】

    4

    【数据范围】

    20%的数据 n<=1000,m<=2000
    100%的数据 n<=100000,m<=100000
    1=<u,v<=n,1=<w<=1000

    思路

    考场上先看的T2,打了暴力发现转移很好维护,于是写出了DP,然后发现m大点矩阵快速幂就行了。

    具体来说,优美的字符串一定可以表示成许多优美的子串,那么只需要计算出每个长度的优美字符串的个数。这个长度不会超过(lfloorlog_2 n floor+1)(O(n log n))DP预处理,(O(log^3 nlog m))矩阵转移。

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
        while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    using namespace std;
    
    co int N=1e6+1,mod=1e9+7;
    int add(int x,int y) {return (x+=y)>=mod?x-mod:x;}
    int mul(int x,int y) {return (ll)x*y%mod;}
    int fpow(int x,int k){
    	int re=1;
    	for(;k;x=mul(x,x),k>>=1)
    		if(k&1) re=mul(re,x);
    	return re;
    }
    int n,lg,f[21][N];
    int A[20][20],ANS[20][20],c[20][20];
    void mul(int a[20][20],int b[20][20]){
    	for(int k=0;k<lg;++k)
    		for(int i=0;i<lg;++i)if(a[i][k])
    			for(int j=0;j<lg;++j)if(b[k][j])
    				c[i][j]=add(c[i][j],mul(a[i][k],b[k][j]));
    	for(int i=0;i<lg;++i)
    		for(int j=0;j<lg;++j) b[i][j]=c[i][j],c[i][j]=0;
    }
    ll m;
    int main(){
    	freopen("string.in","r",stdin),freopen("string.out","w",stdout);
    	lg=log(read(n))/log(2)+1,read(m);
    	fill(f[1]+n/2+1,f[1]+n+1,1);
    	for(int i=n;i>=1;--i) f[1][i]=add(f[1][i],f[1][i+1]);
    	for(int k=2;k<=lg;++k)
    		for(int i=n/2;i>=1;--i) f[k][i]=add(f[k-1][2*i],f[k][i+1]);
    	ANS[0][0]=1;
    	for(int i=1;i<lg;++i)
    		for(int k=1;k<=lg&&k<=i;++k) ANS[i][0]=add(ANS[i][0],mul(ANS[i-k][0],f[k][1]));
    	if(m<lg) return printf("%d
    ",ANS[m][0]),0;
    	for(int i=0;i<lg-1;++i) A[i][i+1]=1;
    	for(int i=0;i<lg;++i) A[lg-1][i]=f[lg-i][1];
    	m-=lg-1;
    	for(;m;m>>=1,mul(A,A))
    		if(m&1) mul(A,ANS);
    	return printf("%d
    ",ANS[lg-1][0]),0;
    }
    

    然后去看T1,发现是伪期望。把求和式展开,只需要维护序列(a[i],i*a[i],i^2*a[i])的区间和就行了。上线段树。

    时间复杂度(O(m log n))

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
        while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    using namespace std;
    
    co int N=1e5;
    int n,m;
    ll f(int i,int n){
    	if(i==2) return (ll)n*(n+1)*(2*n+1)/6;
    	if(i==1) return (ll)n*(n+1)/2;
    	return assert(i==0),n;
    }
    struct node{
    	ll a[3];
    	void add(int l,int r,int v){
    		for(int i=0;i<3;++i) a[i]+=(f(i,r)-f(i,l-1))*v;
    	}
    	node operator+(co node&b)co{
    		node c;
    		for(int i=0;i<3;++i) c.a[i]=a[i]+b.a[i];
    		return c;
    	}
    }s[N*4];
    ll t[N*4];
    #define lc (x<<1)
    #define rc (x<<1|1)
    void down(int x,int l,int r){
    	if(t[x]){
    		int mid=l+r>>1;
    		s[lc].add(l,mid,t[x]),t[lc]+=t[x];
    		s[rc].add(mid+1,r,t[x]),t[rc]+=t[x];
    		t[x]=0;
    	}
    }
    void add(int x,int l,int r,int ql,int qr,int v){
    	if(ql<=l&&r<=qr) return s[x].add(l,r,v),t[x]+=v,void();
    	down(x,l,r);
    	int mid=l+r>>1;
    	if(ql<=mid) add(lc,l,mid,ql,qr,v);
    	if(qr>mid) add(rc,mid+1,r,ql,qr,v);
    	s[x]=s[lc]+s[rc];
    }
    node qry(int x,int l,int r,int ql,int qr){
    	if(ql<=l&&r<=qr) return s[x];
    	down(x,l,r);
    	int mid=l+r>>1;
    	if(qr<=mid) return qry(lc,l,mid,ql,qr);
    	if(ql>mid) return qry(rc,mid+1,r,ql,qr);
    	return qry(lc,l,mid,ql,qr)+qry(rc,mid+1,r,ql,qr);
    }
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    int main(){
    	freopen("snaker.in","r",stdin),freopen("snaker.out","w",stdout);
    	read(n),read(m);
    	for(int l,r,x;m--;){
    		static char o[2];scanf("%s",o);
    		if(o[0]=='C'){
    			read(l),read(r),read(x);
    			add(1,1,n-1,l,r-1,x);
    		}
    		else{
    			read(l),read(r);
    			node s=qry(1,1,n-1,l,r-1);
    			ll sum=-s.a[2]+s.a[1]*(l+r-1)+s.a[0]*r*(1-l),cnt=ll(r-l+1)*(r-l)/2,g=gcd(sum,cnt);
    			printf("%lld/%lld
    ",sum/g,cnt/g);
    		}
    	}
    	return 0;
    }
    

    T3是个废题,出题人说这种支配节点可以用支配树算法求得。也可以做个最短路径条数DP,若一个点的到起点和终点的最短路径条数乘积等于起点到终点的最短路条数,那么这个点就是支配节点。为了避免条数爆long long,出题人用了hash。

    但是我随机化走最短路可以得到90分的好成绩,并且只随机2次都是对的。还有10分是一条链,跑2次就会TLE了。但是考试的时候我把那个有向图看成无向图了,所以值得了30分。

    还有外校大佬用了各种假算法爆掉了这道题。

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
        while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    using namespace std;
    typedef pair<int,int> pii;
    
    co int N=1e5+1,INF=0x3f3f3f3f;
    int n,m,dis[N];
    vector<pii> e[N],r[N];
    priority_queue<pii> pq;
    queue<int> q;
    vector<int> g[N];
    set<int> s;
    void dijkstra(){
    	fill(dis+2,dis+n+1,INF);
    	pq.push(pii(-dis[1],1));
    	while(pq.size()){
    		int d=-pq.top().first,u=pq.top().second;pq.pop();
    		if(d>dis[u]) continue;
    		for(int i=0;i<e[u].size();++i){
    			int v=e[u][i].first,w=e[u][i].second;
    			if(dis[v]>d+w) dis[v]=d+w,pq.push(pii(-dis[v],v));
    		}
    	}
    }
    void bfs(){
    	q.push(n);
    	while(q.size()){
    		int u=q.front();q.pop();
    		for(int i=0;i<r[u].size();++i){
    			int v=r[u][i].first,w=r[u][i].second;
    			if(dis[v]+w==dis[u]) g[u].push_back(v),q.push(v);
    		}
    	}
    }
    set<int> s1,s2;
    void dfs0(int u){
    	s1.insert(u);
    	if(u==1) return;
    	dfs0(g[u][rand()*rand()%g[u].size()]);
    }
    void dfs(int u){
    	if(s1.find(u)!=s1.end()) s2.insert(u);
    	if(u==1) return;
    	dfs(g[u][rand()*rand()%g[u].size()]);
    }
    int main(){
    	freopen("c.in","r",stdin),freopen("c.out","w",stdout);
    	read(n),read(m);
    	int cnt=0;
    	for(int u,v,w;m--;){
    		read(u),read(v),read(w);
    		if(abs(u-v)<=1) ++cnt;
    		e[u].push_back(pii(v,w)),r[v].push_back(pii(u,w));
    	}
    	dijkstra();
    	if(dis[n]==INF) return puts("-1"),0;
    	bfs(),dfs0(n);
    	for(int i=1,t=1;i<=t;++i) dfs(n),s1=s2;
    	return printf("%llu
    ",s1.size()),0;
    }
    
  • 相关阅读:
    Oracle手工建库
    php如何在某个时间上加一天?一小时? 时间加减
    JavaScript:this是什么?
    ping广播地址会如何(转)
    用CSS3实现文字描边
    vue二十七:vue基础之过滤器
    vue二十六:vue基础之vue生命周期
    vue二十五:vue基础之单个元素过渡和多个元素过渡
    vue二十五:vue基础之slot插槽和具名插槽
    vue二十四:vue基础之动态组件
  • 原文地址:https://www.cnblogs.com/autoint/p/10639771.html
Copyright © 2011-2022 走看看