考前做题笔记

[KDOI-10]商店砍价

考虑dp,钦定全用操作 1,容易由 vi105 发现只有剩下的数位小于 6 时用操作 2 才更优。于是我们设 fi,j 为考虑完第 i 位剩下 j 个数用操作 2 能减小的最大代价,并从高位向低位考虑。

转移方程很显然,选或不选用操作 2 能减小的代价取最大值,对于数位 x 剩下 j 位,因为是从低到高枚举用操作 2 即保留这一位的代价为 x×10j1。所以转移方程为 fi,j=max(fi+1,j,fi+1,j1+viai×10j1) ai 为输入数从左向右数第 i 位。

Code:

#include<bits/stdc++.h>
#define gt getchar
#define pt putchar
#define int long long
#define ull unsigned long long
#define fst first
#define snd second
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
typedef pair<int,int> pii;
const double eps=1e-6;
inline bool pts(char ch){return ch>=48&&ch<=57;}
inline int read(){
	bool f=0;int x=0;char ch;
	ch=gt();
	while(!pts(ch)&&ch!=EOF){if(ch=='-')f=1;ch=gt();}
	while(pts(ch)){x*=10;x+=(ch-48);ch=gt();}
	if(f)return -x;
	else return x;
}
template<class T>
inline void print(T x){
	char s[114];
	int top=0;
	if(x<0)pt('-');
	do{
		top++;
		if(x>=0)s[top]=(x%10)+48;
		else s[top]=(-(x%10)+48);
		x/=10;
	}while(x);
	while(top){pt(s[top]);top--;}
}
int f[100005][10];
int v[10];
//|n|>5时1一定优,设f[i][j]为考虑到第i位利用策略二答案减小的值
void solve(){
    memset(f,-1,sizeof(f));
    string s;
    cin>>s;
    int len=s.size();
    s=' '+s;
    int sum=0;
    for(int i=1;i<=9;i++)v[i]=read();
    f[len+1][0]=0;
    for(int i=len;i>=1;i--){
        sum+=v[s[i]-'0'];
        f[i][0]=f[i+1][0];
        for(int j=1;j<=5;j++){
            f[i][j]=max(f[i][j],f[i+1][j]);
            f[i][j]=max(f[i+1][j],f[i+1][j-1]+v[s[i]-'0']-(s[i]-'0')*(int)powl(10,j-1));
        }
    }
    int maxn=-1;
    for(int j=1;j<=5;j++)
        maxn=max(maxn,f[1][j]);
    cout<<min(sum,sum-maxn)<<'\n';
}
signed main(){
    int c=read(),T=read();
    while(T--)solve();
    return 0;
}

打字练习

把范文和输入分别读入,读入时用 getline,然后把每行字符串处理掉退格键加入到 vector 中方便比较,记正确的字符数为 cnt,答案即为 cnt×60÷t+0.5

坑点:范文也有退格键,处理退格时注意写法。

Code:

#include<bits/stdc++.h>
#define gt getchar
#define pt putchar
#define int long long
#define ull unsigned long long
#define fst first
#define snd second
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
typedef pair<int,int> pii;
const double eps=1e-6;
inline bool pts(char ch){return ch>=48&&ch<=57;}
inline int read(){
	bool f=0;int x=0;char ch;
	ch=gt();
	while(!pts(ch)&&ch!=EOF){if(ch=='-')f=1;ch=gt();}
	while(pts(ch)){x*=10;x+=(ch-48);ch=gt();}
	if(f)return -x;
	else return x;
}
template<class T>
inline void print(T x){
	char s[114];
	int top=0;
	if(x<0)pt('-');
	do{
		top++;
		if(x>=0)s[top]=(x%10)+48;
		else s[top]=(-(x%10)+48);
		x/=10;
	}while(x);
	while(top){pt(s[top]);top--;}
}
string fw[10005];
string sr[10005];
vector<char>v1[10005],v2[10005];
signed main(){
    int cnt=0;
    while(true){   
        cnt++;
        getline(cin,fw[cnt]);
        if(fw[cnt]=="EOF")break;
        for(char c:fw[cnt]){
            if(c!='<')v1[cnt].push_back(c);
            else if(c=='<'&&v1[cnt].size()>0)v1[cnt].pop_back();//这两个if else顺序是坑点
        }
    }
    int tnc=0;
    while(true){
        tnc++;
        getline(cin,sr[tnc]);
        if(sr[tnc]=="EOF")break;
        for(char c:sr[tnc]){
            if(c!='<')v2[tnc].push_back(c);
            else if(c=='<'&&v2[tnc].size()>0)v2[tnc].pop_back();
        }
    }
    int ans=0;
    for(int i=1;i<=min(cnt,tnc);i++)
        for(int j=0;j<min(v2[i].size(),v1[i].size());j++)
            if(v1[i][j]==v2[i][j])ans++;
            //cout<<(char)v1[i][j]<<' '<<(char)v2[i][j]<<'\n';
    int T=read();
    cout<<(int)(1.0*ans/T*60.0+0.5);
    return 0;
}

「Daily OI Round 3」Tower

题目中的 e 实际上就是以 (i,j) 为中心,在 A 国领地内的正方形的边长的最大值。

第一问是简单的,直接利用二维前缀和 O(n3) 枚举即可。

第二问我们考虑求每个为平地的点对答案的贡献。假设点 B 在以 A 为中心的某个合法正方形的边缘,我们记点 A 与点 BA距离d,如果 B 变成山地,那么以 A 为中心的 e 会从 k 变为 k1,所以它对答案的贡献会从 k2 变为 (k1)2,我们把原枚举到的正方形内所有点的贡献都减去 2k1 即可,这一步可以用二维差分来做。

最终实现时间度为 O(n3)

Code:

#include<bits/stdc++.h>
#define gt getchar
#define pt putchar
#define int long long
#define ull unsigned long long
#define fst first
#define snd second
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
typedef pair<int,int> pii;
const double eps=1e-6;
inline bool pts(char ch){return ch>=48&&ch<=57;}
inline int read(){
	bool f=0;int x=0;char ch;
	ch=gt();
	while(!pts(ch)&&ch!=EOF){if(ch=='-')f=1;ch=gt();}
	while(pts(ch)){x*=10;x+=(ch-48);ch=gt();}
	if(f)return -x;
	else return x;
}
template<class T>
inline void print(T x){
	char s[114];
	int top=0;
	if(x<0)pt('-');
	do{
		top++;
		if(x>=0)s[top]=(x%10)+48;
		else s[top]=(-(x%10)+48);
		x/=10;
	}while(x);
	while(top){pt(s[top]);top--;}
}
int a[605][605];
int sum[605][605];
int df[605][605];
void update(int x1,int y1,int x2,int y2,int v){
    df[x1][y1]+=v;
    df[x2+1][y1]-=v;
    df[x1][y2+1]-=v;
    df[x2+1][y2+1]+=v;
}
int getsum(int x1,int y1,int x2,int y2){
    return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}
int ans=0;
signed main(){
    int n=read(),m=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            char ch;
            cin>>ch;
            if(ch=='.')a[i][j]=0;
            else a[i][j]=1;
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            update(i,j,i,j,a[i][j]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int e=0;
            while(i+e<=n&&j+e<=m&&i-e>=1&&j-e>=1){
                if(getsum(i-e,j-e,i+e,j+e))break;
                e++;
            }
            ans+=e*e;
            e=0;
            while(i+e<=n&&j+e<=m&&i-e>=1&&j-e>=1){
                if(getsum(i-e,j-e,i+e,j+e))break;
                update(i-e,j-e,i+e,j+e,-(2*e+1));
                e++;
            }
        }
    }
    cout<<ans<<'\n';
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            df[i][j]+=df[i-1][j]+df[i][j-1]-df[i-1][j-1];
            if(a[i][j])cout<<-1<<' ';
            else cout<<ans+df[i][j]<<' ';
        }
        cout<<'\n';
    }
    return 0;
}

[GXOI/GZOI2019] 旅行者

本题将单源最短路拓展到了多源最短路径上。

暴力是显然的,考虑优化。

跑两遍最短路,第一遍建图表示从兴趣城市出发到每个点的最短路 diststi 表示到 i 最短路是从哪里来的;第二遍建反图表示从每个点出发到兴趣城市的最短路 tsidedi 表示从 i 出发的最短路走到了哪。

求完之后对每条边 (s,e,d) 考虑,如果 sts=ede,说明在环上,忽略;否则维护答案(将答案与 distu+tsidv+d 取最小值),可证明这一定是最短路。

注意将初始值开大点,如 1018

Code:

#include<bits/stdc++.h>
#define gt getchar
#define pt putchar
#define int long long
#define ull unsigned long long
#define fst first
#define snd second
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
typedef pair<int,int> pii;
const double eps=1e-6;
inline bool pts(char ch){return ch>=48&&ch<=57;}
inline int read(){
	bool f=0;int x=0;char ch;
	ch=gt();
	while(!pts(ch)&&ch!=EOF){if(ch=='-')f=1;ch=gt();}
	while(pts(ch)){x*=10;x+=(ch-48);ch=gt();}
	if(f)return -x;
	else return x;
}
template<class T>
inline void print(T x){
	char s[114];
	int top=0;
	if(x<0)pt('-');
	do{
		top++;
		if(x>=0)s[top]=(x%10)+48;
		else s[top]=(-(x%10)+48);
		x/=10;
	}while(x);
	while(top){pt(s[top]);top--;}
}
const int MAXN=5e5+5;
struct Edge{
    int s,e,d;
}edge[MAXN];
int n,m,k;
int dist[MAXN];
int tsid[MAXN];
bool vis[MAXN];
int st1[MAXN],ed2[MAXN];//st1_i到i最短路的兴趣城市,ed2_i到i到哪个兴趣城市
vector<pii>z[MAXN];
priority_queue<pii,vector<pii>,greater<pii> >h;
void add_edge(int s,int e,int d){
	z[s].emplace_back(e,d); 
}
vector<pii>g[MAXN];
void Add_Edge(int s,int e,int d){
	g[s].emplace_back(e,d); 
}
int c[MAXN];
void dijkstra1(){
	while(h.size()){
		int p=h.top().second;
		h.pop();
        if(vis[p])continue;
		vis[p]=true;
		for(int j=0;j<z[p].size();j++){
			int q=z[p][j].first;
			int d=z[p][j].second;
			if(dist[q]>dist[p]+d){
				dist[q]=dist[p]+d;
                st1[q]=st1[p];
				h.push(make_pair(dist[q],q));
			}
		} 
	}
} 
void dijkstra2(){
	while(h.size()){
		int p=h.top().second;
		h.pop();
        if(vis[p])continue;
		vis[p]=true;
		for(int j=0;j<g[p].size();j++){
			int q=g[p][j].first;
			int d=g[p][j].second;
			if(tsid[q]>tsid[p]+d){
				tsid[q]=tsid[p]+d;
                ed2[q]=ed2[p];
				h.push(make_pair(tsid[q],q));
			}
		} 
	}
} 
void solve(){
	n=read(),m=read(),k=read();
    //cout<<n<<' '<<m<<' '<<k<<'\n';
	for(int i=1;i<=m;i++){
		edge[i].s=read(),edge[i].e=read(),edge[i].d=read();
		add_edge(edge[i].s,edge[i].e,edge[i].d);
        Add_Edge(edge[i].e,edge[i].s,edge[i].d);
	}
	for(int i=1;i<=k;i++)c[i]=read();
    for(int i=1;i<=n;i++)dist[i]=1e18;
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=k;i++)h.push(make_pair(0,c[i])),dist[c[i]]=0,st1[c[i]]=c[i];
    dijkstra1();
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++)tsid[i]=1e18;
    for(int i=1;i<=k;i++)h.push(make_pair(0,c[i])),tsid[c[i]]=0,ed2[c[i]]=c[i];
    dijkstra2();
    int ans=1e18;
    for(int i=1;i<=m;i++){
        if(st1[edge[i].s]==ed2[edge[i].e]||!st1[edge[i].s]||!ed2[edge[i].e])continue;
        ans=min(ans,dist[edge[i].s]+tsid[edge[i].e]+edge[i].d);
    }   
    cout<<ans<<'\n';
    for(int i=0;i<=n+1;i++)z[i].clear(),g[i].clear();
}
signed main(){
    int T=read();
    while(T--)solve();
    return 0;
}

[ABC007D]Small Multiple

每一个数都是可以由 1 通过 ×10+1 得出来的,容易发现进行前者完的数位和相比原数不变,进行后者完则数位和比原数大 1。于是我们将原问题转化为图论问题,在 modk 意义下进行求解,我们把 1k1 每一个数看成点,向 i×10 连一条权值为 0 的边,向 i+1 连一条权值为 1 的边,然后从 1 开始跑最短路,因为是模 k 意义下进行的计算,所以最后答案为 dis0+1

Code:

#include<bits/stdc++.h>
#define gt getchar
#define pt putchar
#define int long long
#define ull unsigned long long
#define fst first
#define snd second
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
typedef pair<int,int> pii;
const double eps=1e-6;
inline bool pts(char ch){return ch>=48&&ch<=57;}
inline int read(){
	bool f=0;int x=0;char ch;
	ch=gt();
	while(!pts(ch)&&ch!=EOF){if(ch=='-')f=1;ch=gt();}
	while(pts(ch)){x*=10;x+=(ch-48);ch=gt();}
	if(f)return -x;
	else return x;
}
template<class T>
inline void print(T x){
	char s[114];
	int top=0;
	if(x<0)pt('-');
	do{
		top++;
		if(x>=0)s[top]=(x%10)+48;
		else s[top]=(-(x%10)+48);
		x/=10;
	}while(x);
	while(top){pt(s[top]);top--;}
}
const int MAXN=1e6+5;
int k;
int dist[MAXN];
bool vis[MAXN];
vector<pii>z[MAXN];
priority_queue<pii,vector<pii>,greater<pii> >h;
void add_edge(int s,int e,int d){
	z[s].emplace_back(e,d); 
}
void dijkstra(int s){
	memset(dist,0x3f,sizeof(dist));
	dist[s]=0;
    h.push(make_pair(0,s));
	while(h.size()){
		int p=h.top().second;
		h.pop();
        if(vis[p])continue;
		vis[p]=true;
		for(int j=0;j<z[p].size();j++){
			int q=z[p][j].first;
			int d=z[p][j].second;
			if(dist[q]>dist[p]+d){
				dist[q]=dist[p]+d;
				h.push(make_pair(dist[q],q));
			}
		} 
	}
} 
signed main(){
	k=read();
	for(int i=0;i<=k-1;i++){
        add_edge(i,i*10%k,0);
        add_edge(i,(i+1)%k,1);
    }
    dijkstra(1);
    cout<<dist[0]+1;
	return 0;
}
posted @   FinderHT  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示