1001.Cut The Wire
由题意:
1.当x为偶数时,与x/2进行连边
2.当x为奇数时,与3*x + 1连边
现在我们需要计算有多少条边(a, b),a <= n && b > n
模拟即可
#include1009.Command Sequence(模拟)#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那么就答案加上即可
#include1007.Function(二次函数性质 + 模拟)#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>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]的范围所以我们直接分情况讨论二次函数即可
#include1002.Time-division Multiplexing(双指针+数组模拟)#define ll long long using namespace std; const int maxn = 1e6 + 10; vector 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个字符串的每一种元素。
我只需要先把这个串构造出来,然后利用双指针进行移动就能求出来答案
#include1006.Power sum(构造)#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进行分情况讨论就可以了
#include1012.Remove(数论的亿点点思路)#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之后再进行逆过来求解就好了
#include1011.Shooting Bricks(多维度dp)#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("%llun",ans); } int main(){ // freopen("2.in","r",stdin); int t; scanf("%d",&t); while(t--)solve(); }
1011.Shooting Bricks
洛谷有原题而且感觉洛谷讲解的很好^ _ ^所以给大家提供链接去洛谷学习一下有很多种写法洛谷题解链接
#include1008.GCD on Sequence(线段树 + 质数)#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("%dn",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 #define x first #define y second using namespace std; const int maxn = 1e5 + 5; ll a[maxn],pos[maxn],ans[maxn]; vector 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 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("%lldn",ans[i]); } } int main(){ // freopen("2.in","r",stdin); init(1e5); int t; sc("%d",&t); while(t--)solve(); }



