1001.Cut The Wire
由题意:
1.当x为偶数时,与x/2进行连边
2.当x为奇数时,与3*x + 1连边
现在我们需要计算有多少条边(a, b),a <= n && b > n
模拟即可
#include
#define ll long long
using namespace std;
int main(){
// freopen("2.in","r",stdin);
int t;
cin >> t;
while(t--){
ll n;
cin >> n;
//连边
//我先把偶数进行计算完 就是 > n的偶数跟 <= n进行连边
ll ans = n / 2 + (n % 2 != 0);
//计算奇数的边界
// 3x + 1 = y
// x = (y - 1)/3;
//[x , n]之间的奇数
ll size = (n - 1) / 3;
//之后需要减去与偶数之间重复的地方即可
ans += (n - (size + (size % 2 == 1)))/2 + (n % 2) ;
cout << ans << endl;
}
}
1009.Command Sequence
由题意:
给你一个移动序列包含四种字母(U向上 D向下 L向左 R向右)的字符串str,和长度n.
让你求有多少种子序列,使得一个点经过这个子序列的操作能够回到原点,例如UDLR就是绕了一周刚好回到原点此时答案+1
利用map即可,我们可以定起始点为(0, 0)之后就可以通过str的操作对(x,y)点进行++,之后到达的点(x,y)的mp[{x,y}]!=0那么就答案加上即可
#include
#define ll long long
using namespace std;
int main(){
// freopen("2.in","r",stdin);
int t;
cin >> t;
while(t--){
int n;
string str;
cin >> n >> str;
//U向上 D向下 L向左 R向右
int x = 0, y = 0;
map< pair<int,int>, int>mp;
mp[make_pair(x,y)]++;
ll ans = 0;
for(int i = 0; i < n; i++){
if(str[i] == 'U')x--;
else if(str[i] == 'D')x++;
else if(str[i] == 'L')y--;
else y++;
if(mp.count(make_pair(x, y)))ans += mp[make_pair(x,y)];
mp[make_pair(x,y)]++;
}
cout << ans << endl;
}
}
1007.Function
由题意:给你一个g(x)的函数定义,之后给你一个由A,B,C,D,x,g(x)等未知数组成的f(x)函数,我们要求f(x)的最小值,有T组例子,每次给你A,B,C,D,N要你求最小值。
解法:我们可以观察n的范围是1e6,所以我的g(x)的范围是[1, 54],我们可以预处理出g(x)值对应的下标i,之后我们对函数f(x)进行转化
f(x) = (Ag(x) + B)x^2 + (Cg(x)^2 + Dg(x))x;
很明显这是一个二次函数形式,我们又直到g(x)只有[1,54]的范围所以我们直接分情况讨论二次函数即可
#include
#define ll long long
using namespace std;
const int maxn = 1e6 + 10;
vector<ll>g[maxn];
int exchange(int x){
int cnt = 0;
while(x){
cnt = cnt + x % 10;
x /= 10;
}
return cnt;
}
void solve(){
ll a,b,c,d,n;
cin >> a >> b >> c >> d >> n;
ll mx = LLONG_MAX;//long long的最大值
//f(x) = (Ag(x) + B)x^2 + (Cg(x)^2 + Dg(x))x;
for(ll j = 1; j <= 54; j++){
ll a1 = a*j + b;//二次函数的开口
ll b1 = c*j*j + d*j;//
if(a1 > 0){
//开口向上 我们就要求对称轴上或者两边的点就是最小的
ll x = -b1/(2*a1);//对称轴
int fin = lower_bound(g[j].begin(),g[j].end(), x) - g[j].begin();
if(fin == g[j].size()){
//找到了末尾
//找第一个小于n的点
fin = upper_bound(g[j].begin(), g[j].end(), n) - g[j].begin() - 1;
if(fin >= 0){
mx = min(mx, a1*g[j][fin]*g[j][fin]+b1*g[j][fin]);
}
} else{
if(g[j][fin] > n){
fin = upper_bound(g[j].begin(), g[j].end(), n) - g[j].begin() - 1;
if(fin >= 0)
mx = min(mx, a1*g[j][fin]*g[j][fin]+b1*g[j][fin]);
}else{
mx = min(mx, a1*g[j][fin]*g[j][fin]+b1*g[j][fin]);
if(fin > 0)
mx = min(mx, a1*g[j][fin - 1]*g[j][fin - 1]+b1*g[j][fin - 1]);
if(fin < g[j].size() - 1)
mx = min(mx, a1*g[j][fin + 1]*g[j][fin + 1]+b1*g[j][fin + 1]);
}
}
}else if(a1 == 0){
//此时一个直线
if(b1 >= 0){
if(g[j].size() > 0 && g[j][0] <= n)
mx = min(mx, a1*g[j][0]*g[j][0]+b1*g[j][0]);
} else{
int x = upper_bound(g[j].begin(), g[j].end(), n) - g[j].begin() - 1;
if(x >= 0)
mx = min(mx, a1*g[j][x]*g[j][x]+b1*g[j][x]);
}
}else{
//开口向下 左右端点即可
if(g[j].size() > 0 && g[j][0] <= n)
mx = min(mx, a1*g[j][0]*g[j][0]+b1*g[j][0]);
int x = upper_bound(g[j].begin(), g[j].end(), n) - g[j].begin() - 1;
if(x >= 0)
mx = min(mx, a1*g[j][x]*g[j][x]+b1*g[j][x]);
}
}
cout << mx << endl;
}
int main(){
// freopen("2.in","r",stdin);
for(int i = 1; i <= 1e6; i++){
int x = exchange(i);
g[x].push_back(i);
}
int t;
cin >> t;
while(t--)solve();
}
1002.Time-division Multiplexing
题意:给你n个字符串,让你以它的方式进行构造一个字符串
例子:
2
abc
bd
先把长度都变成n个字符串长度的lcm
abcabc
bdbdbd
那么构造出来的字符串str为abbdcbadbbcd
之后然我们求在str中(str可以进行多次与本身连接即循环节),求最小长度的子串使得包含n个字符串的每一种元素。
我只需要先把这个串构造出来,然后利用双指针进行移动就能求出来答案
#include
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
ll gcd(ll a, ll b){
return b?gcd(b, a%b):a;
}
ll lcm(ll a, ll b){
return a/gcd(a,b)*b;
}
string str[105];
int mp[26],cnt[26];
void solve(){
int n;
cin >> n;
memset(mp, 0, sizeof mp);
memset(cnt, 0, sizeof cnt);
int len = 1;
for(int i = 0; i < n; i++){
cin >> str[i];
int s = str[i].size();
len = lcm(len, s);
for(int j = 0; j < s; j++){
mp[str[i][j] - 'a']++;
}
}
string res = "";
for(int i = 0; i < len; i++){
for(int j = 0; j < n; j++)
res += str[j][i % str[j].size()];
}
int sz = 0;
for(int i = 0; i < 26; i++)if(mp[i])sz++;
res += res;
int ans = 0x3f3f3f3f;
int l = 0;
int flag = 0;
for(int i = 0; i < res.size(); i++){
int x = res[i] - 'a';
cnt[x]++;
if(cnt[x] == 1){
flag ++;
//包含了全部元素
if(flag == sz){
ans = min(ans,i - l + 1);
while(true){
int x = res[l] - 'a';
cnt[x]--;
if(cnt[x] == 0){
l ++ ;
flag--;
break;
}else{
l++;
ans = min(ans, i - l + 1);
}
}
}
}
}
cout << ans << endl;
}
int main(){
// freopen("2.in","r", stdin);
IOS;
int t;
cin >> t;
while(t--)solve();
}
1006.Power sum
由题意:让你构造出k个数使得题目的方程式之和=n
我们可以观察到a_i的值只能为1或-1
之后我们对i^2进行考虑,我们可以列出来
1 4 9 16 25 36 …
考虑差值 3 5 7 9 11 13 …
那么我们如果要构造出4可以用四个数构造出来(5 - 3) + (9 - 7)
那么我们就可以对n % 4进行分情况讨论就可以了
#include
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
void solve(){
int n;
cin >> n;
//每产生4我们可以用四个数得到
int x = n/4;
int y = n%4;
string ans = "";
for(int i = 1; i <= x; i++){
ans += "1001";
}
if(y == 0){
cout << n << endl;
} else if(y == 1){
cout << n << endl;
ans = "1" + ans;
}else if(y == 2){
cout << n + 2 << endl;
ans = "0001" + ans;
}else{
cout << n - 1 << endl;
ans = "01" + ans;
}
cout << ans << endl;
}
int main(){
// freopen("2.in","r",stdin);
IOS;
int t;
cin >> t;
while(t--)solve();
}
1012.Remove
题意:给你一个质数集合P和一个整数n,n表示有n个石头,每一次操作你可以选择质数P的集合的一个元素,之后你可以在这堆石头(剩余m)里面取m % p[i]个石头,你需要用最小的回合进行拿掉石子,答案按照题意构造方式进行处理出来
解法:我们可以先把质数集合进行排序,之后我们可以倒过来考虑,假设当前剩余石子为m,当前操作质数为p,那么我们前一次操作的数就为[x + 1, x + p - 1],通过这样逆推我们可以得到a_1 - a_n之后再进行逆过来求解就好了
#include
#define sc scanf
#define pr printf
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define INF 0x7fffffffffffffff
#define inf 0x3f3f3f3f
#define ull unsigned long long
using namespace std;
const int maxn = 2e6 + 5;
int p[maxn];
int a[maxn];
void solve(){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)p[i] = a[i] = 0;
for(int i = 1; i <= m; i++)scanf("%d",&p[i]);
sort(p+1,p+1+m);
int r = 0;
for(int l = 0; l <= n;l = r,r = 0){
for(int i = 1; i <= m; i++){
int flag = (l/p[i])*p[i] + p[i] - 1;
if(r < flag)r = flag;
}
for(int i = l+1; i <= r; i++)
a[i] = a[l] + 1;
if(l == r)break;
}
ull ans = 0,res = 1;
for(int i = n; i >= 1; i--){
ans = ans + a[i]*res;
res *= 23333;
}
printf("%llu\n",ans);
}
int main(){
// freopen("2.in","r",stdin);
int t;
scanf("%d",&t);
while(t--)solve();
}
1011.Shooting Bricks
洛谷有原题而且感觉洛谷讲解的很好^ _ ^所以给大家提供链接去洛谷学习一下有很多种写法洛谷题解链接
#include
#define sc scanf
#define pr printf
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define INF 0x7fffffffffffffff
#define inf 0x3f3f3f3f
#define ull unsigned long long
using namespace std;
const int maxn = 205;
int dp[maxn][maxn][2];
int dp1[maxn][maxn][2];
int a[maxn][maxn],vis[maxn][maxn];
void solve(){
int n,m,k;
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
memset(dp1,0,sizeof(dp1));
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char op[3];
scanf("%d%s",&a[i][j],op);
if(op[0]=='Y')
vis[i][j]=1;
}
}
for(int i=1;i<=m;i++){
//cnt表示实际用的子弹个数
int cnt=0;
for(int j=n;j>=1;j--){
if(vis[j][i])
dp[i][cnt][0]+=a[j][i];
else{
cnt++;
dp[i][cnt][0]=dp[i][cnt-1][0]+a[j][i];
dp[i][cnt][1]=dp[i][cnt-1][0]+a[j][i];
}
}
}
for(int i=1;i<=m;i++){
for(int j=0;j<=k;j++){
//p表示第i列可以用p颗子弹
for(int p=0;p<=j&&p<=n;p++){
//这个循环的意思是,给第i列分配p颗子弹,给前i-1列分配j-p颗子弹
dp1[i][j][0]=max(dp1[i][j][0],dp1[i-1][j-p][0]+dp[i][p][0]);
if(p){
//如果p>=1,那么第i列可以借一些子弹给前i-1列
dp1[i][j][1]=max(dp1[i][j][1],dp1[i-1][j-p][0]+dp[i][p][1]);
}
if(j-p){
//如果j-p>=1,那么前i-1列可以借一些子弹给第i列
dp1[i][j][1]=max(dp1[i][j][1],dp1[i-1][j-p][1]+dp[i][p][0]);
}
}
}
}
printf("%d\n",dp1[m][k][1]);
}
int main(){
// freopen("2.in","r",stdin);
int t;
// scanf("%d")
scanf("%d",&t);
while(t--)solve();
}
1008.GCD on Sequence
由题意:定义v(l, r) = maxl≤i
#include
#define ll long long
#define ls u<<1
#define rs u<<1|1
#define sc scanf
#define pr printf
#define pii pair<int,int>
#define x first
#define y second
using namespace std;
const int maxn = 1e5 + 5;
ll a[maxn],pos[maxn],ans[maxn];
vector<int> fac[maxn];
void init(int n){
for(int i = n; i >= 1; i--){
for(int j = i; j <= n; j += i){
fac[j].push_back(i);
}
}
}
struct Segtree{
ll sum,min,max;
pii laz;
}tr[maxn << 2];
void pushup(int u){
tr[u].min = min(tr[ls].min,tr[rs].min);
tr[u].max = max(tr[ls].max,tr[rs].max);
tr[u].sum = tr[ls].sum + tr[rs].sum;
}
void modify(int u, int l, int r, pii laz){
tr[u].laz = laz;
tr[u].sum = (r - l + 1)*1ll*laz.y;
tr[u].max = tr[u].min = laz.x;
}
void pushdown(int u, int l, int r){
if(tr[u].laz.x){
int mid = l + r >> 1;
modify(ls, l, mid, tr[u].laz);
modify(rs, mid+1, r, tr[u].laz);
tr[u].laz.x = 0;
}
}
void update(int u, int l, int r,int x, int y, int z, int i){
if(tr[u].min >= z)return ;
if(x <= l && r <= y && tr[u].max == tr[u].min){
ans[tr[u].max] += 1ll*i*(r - l + 1) - tr[u].sum;
modify(u, l, r, make_pair(z, i));
return ;
}
pushdown(u, l, r);
int mid = l + r >> 1;
if(x <= mid)update(ls, l, mid, x, y, z, i);
if(y > mid)update(rs, mid + 1, r, x, y, z, i);
pushup(u);
}
void solve(){
int n;
sc("%d",&n);
for(int i = 1; i <= n * 4; i++){
if(i <= n + 1)ans[i] = pos[i] = 0;
tr[i].laz.x = tr[i].laz.y = tr[i].max = tr[i].min = tr[i].sum = 0;
}
for(int i = 1; i <= n; i++){
sc("%lld",&a[i]);
vector<int>s;
for(int j = 0; j < fac[a[i]].size(); j++){
if(pos[fac[a[i]][j]]){
if (s.empty() || pos[s.back()] < pos[fac[a[i]][j]]) s.push_back(fac[a[i]][j]);
}
}
int last = 0;
for(int j = 0; j < s.size(); j++){
int x = s[j];
update(1, 1, n, last + 1, pos[x], x, i);
last = pos[x];
}
for(int j = 0; j < fac[a[i]].size(); j++){
pos[fac[a[i]][j]] = i;
}
}
update(1, 1, n, 1, n, n + 1, n + 1);
for(int i = 1; i <= n; i++){
printf("%lld\n",ans[i]);
}
}
int main(){
// freopen("2.in","r",stdin);
init(1e5);
int t;
sc("%d",&t);
while(t--)solve();
}