A.题意:100个数字,大小100,问可否从中选出k个不同数字,输出位置
思路:map.count
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int main(){
IO;
int n,k;cin>>n>>k;
vector<int> a;
map<int,int>mp;
forn(i,n){
int x;cin>>x;
if(!mp[x]) a.push_back(i+1);
mp[x]++;
}
if(a.size()>=k){
cout<<"YES"<<'
';
forn(i,k) cout<<a[i]<<' ';
} else cout<<"NO"<<'
';
return 0;
}
B.题意:给100个长度为100的字符串,排序使得前面的每一个字符串前面的字符串为他的的子串。
思路:暴力就可以了,不暴力可以dp+kmp做,substr可以减少代码量,用法为string.(起始位置,长度)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
vector<string>s[100];
map<int,pair<int,int> >mp;
int main(){
IO;
int n;cin>>n;
forn(i,n){
int m;cin>>m;
vector<int>a(m);
int sum = 0;
forn(j,m){
cin>>a[j];
sum+=a[j];
}
forn(j,m)if(mp.count(sum-a[j])){
cout<<"YES"<<'
';
auto ans = mp[sum-a[j]];
cout<< ans.first+1<<' '<<ans.second+1<<'
';
cout<<i+1<<' '<<j+1<<'
';
return 0;
}
forn(j,m)if(!mp.count(sum-a[j]))mp[sum-a[j]] = {i,j};
}
cout<<"NO"<<'
';
return 0;
}
C.题意:2e5个数组,共最多2e5个数,能否删除某两个数组的一个数字,使得这两个数组的sum值相同。
思路:map存,出现答案return
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
vector<string>s[100];
map<int,pair<int,int> >mp;
int main(){
IO;
int n;cin>>n;
forn(i,n){
int m;cin>>m;
vector<int>a(m);
int sum = 0;
forn(j,m){
cin>>a[j];
sum+=a[j];
}
forn(j,m)if(mp.count(sum-a[j])){
cout<<"YES"<<'
';
auto ans = mp[sum-a[j]];
cout<< ans.first+1<<' '<<ans.second+1<<'
';
cout<<i+1<<' '<<j+1<<'
';
return 0;
}
forn(j,m)if(!mp.count(sum-a[j]))mp[sum-a[j]] = {i,j};
}
cout<<"NO"<<'
';
return 0;
}
D.
题意:2e5个数,问最多取多少个数字使得各个数字两两差为2的幂。
思路:取一个数,它右边最多取一个,左边最多取一个。假设取了两个那么必然和本数差2^k和2的幂次方,可以看为二进制的两个不同位置的1,那么这两个差肯定是多个1,除了最小那两个以外。当我们考虑最小的两个会发现,左边取不了。所以最多三个,知道这个定理之后就可以map记录然后枚举。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
map<ll,int>mp;
int main(){
IO;
int n;cin>>n;vector<ll>a(n);forn(i,n){
int x; cin>>x;a[i] = x;
mp[x] = 1;
}
forn(j,n){
forn(i,32){
ll x = 1ll<<i;
//if(a[j]==5&&i==1) cerr<<a[j]<<' '<<x<<' '<<a[j]+x<<' '<<a[j]+x<<'
';
if(mp.count(x+a[j])&&mp.count(a[j]-x)){
cout<<3<<'
';
cout<<a[j]-x<<' '<<a[j]<<' '<<a[j]+x<<'
';
return 0;
}
}
}
forn(j,n){
forn(i,32){
ll x = 1ll<<i;
if(mp.count(x+a[j])){
cout<<2<<'
';
cout<<a[j]+x<<' '<<a[j]<<'
';
return 0;
}
if(mp.count(a[j]-x)){
cout<<2<<'
';
cout<<a[j]-x<<' '<<a[j]<<'
';
return 0;
}
}
}
cout<<1<<'
'<<a[0]<<'
';
return 0;
}
E.
题意:给一个数字经过一些操作使得它可以被25整除,每次操作可以使相邻两数直接交换位置,不能有前导0,求最小操作次数。
思路:显然末尾只要有00,50,25,75就可以了,那么分类讨论,先移动最近的0或5,在找最近的另一个数字。比如50267,要考虑前导0,那么我们最后判断有前导0的情况找按顺序找第一个非0的数。加上去取min即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
int main(){
IO;
string s,m;cin>>s;
m = s;
int ans = inf,res = inf,pos = 0;
bool ok1 = 0,ok2 = 0;
for(int i = m.size()-1;i>=0;i--){
if(m[i]=='5'){
ok1 = 1;
res = 0;
res+=m.size()-i-1;
pos = i;
break;
}
}
if(res!=inf){
for(int i = pos+1;i<m.size();i++) swap(m[i],m[i-1]);
for(int i = m.size()-2;i>=0;i--){
if(m[i]=='2'||m[i]=='7'){
ok2 = 1;
res+=m.size()-i-2;
pos = i;
break;
}
}
for(int i = pos+1;i<m.size()-1;i++)swap(m[i],m[i-1]);
if(m[0]=='0'){
for(int i = 0;i<m.size()-2;i++){
if(m[i]!='0'){
res+=i;
m[0]='#';
break;
}
}
}
}
if(m[0]!='0'&&ok1&&ok2) ans = res;
res = inf,m = s,ok1=ok2 = 0;
for(int i = m.size()-1;i>=0;i--){
if(s[i]=='0'){
ok1 = 1;
res = 0;
res+=m.size()-i-1;
pos = i;
break;
}
}
if(res!=inf){
for(int i = pos+1;i<m.size();i++) swap(m[i],m[i-1]);
for(int i = m.size()-2;i>=0;i--){
if(m[i]=='5'||m[i]=='0'){
ok2 = 1;
res+=m.size()-i-2;
pos = i;
break;
}
}
for(int i = pos+1;i<m.size()-1;i++)swap(m[i],m[i-1]);
if(m[0]=='0'){
for(int i = 0;i<m.size()-2;i++){
if(m[i]!='0'){
res+=i;
m[0]='#';
break;
}
}
}
}
if(m[0]!='0'&&ok1&&ok2) ans = min(ans,res);
if(ans!=inf) cout<<ans<<'
';
else cout<<-1<<'
';
return 0;
}
F.
题意:一条路从1点走到a点,一次只移动1格。现在有n个区间有雨,你在下雨区间必须打伞。现在上帝给你在m个点都放了伞,每把伞有它的放的位置pi和你的坏感度wi。当你拿一把伞走了1个距离,那么你的心情-wi。你可以随时扔掉伞,如果pi有伞你可以捡伞换伞。问心情最少-多少。
思路:dpij i表示走到第几个点,j表示此时手上用第j个雨伞
每次可以转移这三种:
- i的时候没有雨扔掉伞dpi-1j转移到dpi0
- 继续打伞dpi-1j转移到dpij
- i-1处有新伞换伞dpi-1j转移到dpia[i-1](a表示伞)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 2005;
const int inf = 0x3f3f3f3f;
bool vis[maxn];
int p[maxn],dp[maxn][maxn];
int main(){
IO;
int e,n,m;cin>>e>>n>>m;
memset(dp,inf,sizeof(dp));
forn(i,n){
int l,r;cin>>l>>r;
for(int i = l+1;i<=r;i++) vis[i] = 1;
}
vector<int>w(m+1);
w[0] = inf;
for1(i,m){
int x,y;cin>>x>>y;
w[i] = y;
if(w[p[x]]>y) p[x] = i;
}
dp[0][0] = 0;
for1(i,e){
for(int j = 0;j<=m;j++){
if(!vis[i])dp[i][0] = min(dp[i][0],dp[i-1][j]);
if(j) dp[i][j] = min(dp[i][j],dp[i-1][j]+w[j]);
if(p[i-1]) dp[i][p[i-1]] = min(dp[i][p[i-1]],dp[i-1][j]+w[p[i-1]]);
}
}
int ans = inf;
forn(i,m+1) ans = min(ans,dp[e][i]);
if(ans==inf) cout<<-1<<'
';
else cout<<ans<<'
';
return 0;
}